From f47eec47878f08fadf4581f9724acb7a484845cb Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Tue, 24 Nov 2020 00:04:13 +0100 Subject: [PATCH 001/279] update changelog --- CHANGELOG.md | 46 +++++++ HISTORY.md | 360 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 406 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8b96fb4c3..70e23e0ff8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,48 @@ # Changelog +## [2.14.0](https://github.com/pypeclub/pype/tree/2.14.0) (2020-11-24) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.13.7...2.14.0) + +**Enhancements:** + +- Shot asset build trigger status [\#736](https://github.com/pypeclub/pype/pull/736) +- Maya: add camera rig publishing option [\#721](https://github.com/pypeclub/pype/pull/721) +- Sort instances by label in pyblish gui [\#719](https://github.com/pypeclub/pype/pull/719) +- Synchronize ftrack hierarchical and shot attributes [\#716](https://github.com/pypeclub/pype/pull/716) +- 686 standalonepublisher editorial from image sequences [\#699](https://github.com/pypeclub/pype/pull/699) +- TV Paint: initial implementation of creators and local rendering [\#693](https://github.com/pypeclub/pype/pull/693) +- Render publish plugins abstraction [\#687](https://github.com/pypeclub/pype/pull/687) +- Ask user to select non-default camera from scene or create a new. [\#678](https://github.com/pypeclub/pype/pull/678) +- TVPaint: image loader with options [\#675](https://github.com/pypeclub/pype/pull/675) +- Maya: Camera name can be added to burnins. [\#674](https://github.com/pypeclub/pype/pull/674) +- After Effects: base integration with loaders [\#667](https://github.com/pypeclub/pype/pull/667) +- Harmony: Javascript refactoring and overall stability improvements [\#666](https://github.com/pypeclub/pype/pull/666) + +**Fixed bugs:** + +- TVPaint extract review fix [\#740](https://github.com/pypeclub/pype/pull/740) +- After Effects: Review were not being sent to ftrack [\#738](https://github.com/pypeclub/pype/pull/738) +- Asset fetch second fix [\#726](https://github.com/pypeclub/pype/pull/726) +- Maya: vray proxy was not loading [\#722](https://github.com/pypeclub/pype/pull/722) +- Maya: Vray expected file fixes [\#682](https://github.com/pypeclub/pype/pull/682) + +**Deprecated:** + +- Removed artist view from pyblish gui [\#717](https://github.com/pypeclub/pype/pull/717) +- Maya: disable legacy override check for cameras [\#715](https://github.com/pypeclub/pype/pull/715) + + +## [2.13.7](https://github.com/pypeclub/pype/tree/2.13.7) (2020-11-19) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.13.6...2.13.7) + +**Merged pull requests:** + +- fix\(SP\): getting fps from context instead of nonexistent entity [\#729](https://github.com/pypeclub/pype/pull/729) + +# Changelog + ## [2.13.6](https://github.com/pypeclub/pype/tree/2.13.6) (2020-11-15) [Full Changelog](https://github.com/pypeclub/pype/compare/2.13.5...2.13.6) @@ -789,4 +832,7 @@ A large cleanup release. Most of the change are under the hood. - _(avalon)_ subsets in maya 2019 weren't behaving correctly in the outliner +\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* + + \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* diff --git a/HISTORY.md b/HISTORY.md index d60bd7b0c7..b8b96fb4c3 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,360 @@ +# Changelog + +## [2.13.6](https://github.com/pypeclub/pype/tree/2.13.6) (2020-11-15) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.13.5...2.13.6) + +**Fixed bugs:** + +- Maya workfile version wasn't syncing with renders properly [\#711](https://github.com/pypeclub/pype/pull/711) +- Maya: Fix for publishing multiple cameras with review from the same scene [\#710](https://github.com/pypeclub/pype/pull/710) + +## [2.13.5](https://github.com/pypeclub/pype/tree/2.13.5) (2020-11-12) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.13.4...2.13.5) + +**Enhancements:** + +- 3.0 lib refactor [\#664](https://github.com/pypeclub/pype/issues/664) + +**Fixed bugs:** + +- Wrong thumbnail file was picked when publishing sequence in standalone publisher [\#703](https://github.com/pypeclub/pype/pull/703) +- Fix: Burnin data pass and FFmpeg tool check [\#701](https://github.com/pypeclub/pype/pull/701) + +## [2.13.4](https://github.com/pypeclub/pype/tree/2.13.4) (2020-11-09) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.13.3...2.13.4) + +**Enhancements:** + +- AfterEffects integration with Websocket [\#663](https://github.com/pypeclub/pype/issues/663) + +**Fixed bugs:** + +- Photoshop uhiding hidden layers [\#688](https://github.com/pypeclub/pype/issues/688) +- \#688 - Fix publishing hidden layers [\#692](https://github.com/pypeclub/pype/pull/692) + +**Closed issues:** + +- Nuke Favorite directories "shot dir" "project dir" - not working [\#684](https://github.com/pypeclub/pype/issues/684) + +**Merged pull requests:** + +- Nuke Favorite directories "shot dir" "project dir" - not working \#684 [\#685](https://github.com/pypeclub/pype/pull/685) + +## [2.13.3](https://github.com/pypeclub/pype/tree/2.13.3) (2020-11-03) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.13.2...2.13.3) + +**Enhancements:** + +- TV paint base integration [\#612](https://github.com/pypeclub/pype/issues/612) + +**Fixed bugs:** + +- Fix ffmpeg executable path with spaces [\#680](https://github.com/pypeclub/pype/pull/680) +- Hotfix: Added default version number [\#679](https://github.com/pypeclub/pype/pull/679) + +## [2.13.2](https://github.com/pypeclub/pype/tree/2.13.2) (2020-10-28) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.13.1...2.13.2) + +**Fixed bugs:** + +- Nuke: wrong conditions when fixing legacy write nodes [\#665](https://github.com/pypeclub/pype/pull/665) + +## [2.13.1](https://github.com/pypeclub/pype/tree/2.13.1) (2020-10-23) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.13.0...2.13.1) + +**Enhancements:** + +- move maya look assigner to pype menu [\#292](https://github.com/pypeclub/pype/issues/292) + +**Fixed bugs:** + +- Layer name is not propagating to metadata in Photoshop [\#654](https://github.com/pypeclub/pype/issues/654) +- Loader in Photoshop fails with "can't set attribute" [\#650](https://github.com/pypeclub/pype/issues/650) +- Nuke Load mp4 wrong frame range [\#661](https://github.com/pypeclub/pype/issues/661) +- Hiero: Review video file adding one frame to the end [\#659](https://github.com/pypeclub/pype/issues/659) + +## [2.13.0](https://github.com/pypeclub/pype/tree/2.13.0) (2020-10-18) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.12.5...2.13.0) + +**Enhancements:** + +- Deadline Output Folder [\#636](https://github.com/pypeclub/pype/issues/636) +- Nuke Camera Loader [\#565](https://github.com/pypeclub/pype/issues/565) +- Deadline publish job shows publishing output folder [\#649](https://github.com/pypeclub/pype/pull/649) +- Get latest version in lib [\#642](https://github.com/pypeclub/pype/pull/642) +- Improved publishing of multiple representation from SP [\#638](https://github.com/pypeclub/pype/pull/638) +- Launch TvPaint shot work file from within Ftrack [\#631](https://github.com/pypeclub/pype/pull/631) +- Add mp4 support for RV action. [\#628](https://github.com/pypeclub/pype/pull/628) +- Maya: allow renders to have version synced with workfile [\#618](https://github.com/pypeclub/pype/pull/618) +- Renaming nukestudio host folder to hiero [\#617](https://github.com/pypeclub/pype/pull/617) +- Harmony: More efficient publishing [\#615](https://github.com/pypeclub/pype/pull/615) +- Ftrack server action improvement [\#608](https://github.com/pypeclub/pype/pull/608) +- Deadline user defaults to pype username if present [\#607](https://github.com/pypeclub/pype/pull/607) +- Standalone publisher now has icon [\#606](https://github.com/pypeclub/pype/pull/606) +- Nuke render write targeting knob improvement [\#603](https://github.com/pypeclub/pype/pull/603) +- Animated pyblish gui [\#602](https://github.com/pypeclub/pype/pull/602) +- Maya: Deadline - make use of asset dependencies optional [\#591](https://github.com/pypeclub/pype/pull/591) +- Nuke: Publishing, loading and updating alembic cameras [\#575](https://github.com/pypeclub/pype/pull/575) +- Maya: add look assigner to pype menu even if scriptsmenu is not available [\#573](https://github.com/pypeclub/pype/pull/573) +- Store task types in the database [\#572](https://github.com/pypeclub/pype/pull/572) +- Maya: Tiled EXRs to scanline EXRs render option [\#512](https://github.com/pypeclub/pype/pull/512) +- Fusion basic integration [\#452](https://github.com/pypeclub/pype/pull/452) + +**Fixed bugs:** + +- Burnin script did not propagate ffmpeg output [\#640](https://github.com/pypeclub/pype/issues/640) +- Pyblish-pype spacer in terminal wasn't transparent [\#646](https://github.com/pypeclub/pype/pull/646) +- Lib subprocess without logger [\#645](https://github.com/pypeclub/pype/pull/645) +- Nuke: prevent crash if we only have single frame in sequence [\#644](https://github.com/pypeclub/pype/pull/644) +- Burnin script logs better output [\#641](https://github.com/pypeclub/pype/pull/641) +- Missing audio on farm submission. [\#639](https://github.com/pypeclub/pype/pull/639) +- review from imagesequence error [\#633](https://github.com/pypeclub/pype/pull/633) +- Hiero: wrong order of fps clip instance data collecting [\#627](https://github.com/pypeclub/pype/pull/627) +- Add source for review instances. [\#625](https://github.com/pypeclub/pype/pull/625) +- Task processing in event sync [\#623](https://github.com/pypeclub/pype/pull/623) +- sync to avalon doesn t remove renamed task [\#619](https://github.com/pypeclub/pype/pull/619) +- Intent publish setting wasn't working with default value [\#562](https://github.com/pypeclub/pype/pull/562) +- Maya: Updating a look where the shader name changed, leaves the geo without a shader [\#514](https://github.com/pypeclub/pype/pull/514) + +**Merged pull requests:** + +- Avalon module without Qt [\#581](https://github.com/pypeclub/pype/pull/581) +- Ftrack module without Qt [\#577](https://github.com/pypeclub/pype/pull/577) + +## [2.12.5](https://github.com/pypeclub/pype/tree/2.12.5) (2020-10-14) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.12.4...2.12.5) + +**Enhancements:** + +- Launch TvPaint shot work file from within Ftrack [\#629](https://github.com/pypeclub/pype/issues/629) + +**Merged pull requests:** + +- Harmony: Disable application launch logic [\#637](https://github.com/pypeclub/pype/pull/637) + +## [2.12.4](https://github.com/pypeclub/pype/tree/2.12.4) (2020-10-08) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.12.3...2.12.4) + +**Enhancements:** + +- convert nukestudio to hiero host [\#616](https://github.com/pypeclub/pype/issues/616) +- Fusion basic integration [\#451](https://github.com/pypeclub/pype/issues/451) + +**Fixed bugs:** + +- Sync to avalon doesn't remove renamed task [\#605](https://github.com/pypeclub/pype/issues/605) +- NukeStudio: FPS collecting into clip instances [\#624](https://github.com/pypeclub/pype/pull/624) + +**Merged pull requests:** + +- NukeStudio: small fixes [\#622](https://github.com/pypeclub/pype/pull/622) +- NukeStudio: broken order of plugins [\#620](https://github.com/pypeclub/pype/pull/620) + +## [2.12.3](https://github.com/pypeclub/pype/tree/2.12.3) (2020-10-06) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.12.2...2.12.3) + +**Enhancements:** + +- Nuke Publish Camera [\#567](https://github.com/pypeclub/pype/issues/567) +- Harmony: open xstage file no matter of its name [\#526](https://github.com/pypeclub/pype/issues/526) +- Stop integration of unwanted data [\#387](https://github.com/pypeclub/pype/issues/387) +- Move avalon-launcher functionality to pype [\#229](https://github.com/pypeclub/pype/issues/229) +- avalon workfiles api [\#214](https://github.com/pypeclub/pype/issues/214) +- Store task types [\#180](https://github.com/pypeclub/pype/issues/180) +- Avalon Mongo Connection split [\#136](https://github.com/pypeclub/pype/issues/136) +- nk camera workflow [\#71](https://github.com/pypeclub/pype/issues/71) +- Hiero integration added [\#590](https://github.com/pypeclub/pype/pull/590) +- Anatomy instance data collection is substantially faster for many instances [\#560](https://github.com/pypeclub/pype/pull/560) + +**Fixed bugs:** + +- test issue [\#596](https://github.com/pypeclub/pype/issues/596) +- Harmony: empty scene contamination [\#583](https://github.com/pypeclub/pype/issues/583) +- Edit publishing in SP doesn't respect shot selection for publishing [\#542](https://github.com/pypeclub/pype/issues/542) +- Pathlib breaks compatibility with python2 hosts [\#281](https://github.com/pypeclub/pype/issues/281) +- Updating a look where the shader name changed leaves the geo without a shader [\#237](https://github.com/pypeclub/pype/issues/237) +- Better error handling [\#84](https://github.com/pypeclub/pype/issues/84) +- Harmony: function signature [\#609](https://github.com/pypeclub/pype/pull/609) +- Nuke: gizmo publishing error [\#594](https://github.com/pypeclub/pype/pull/594) +- Harmony: fix clashing namespace of called js functions [\#584](https://github.com/pypeclub/pype/pull/584) +- Maya: fix maya scene type preset exception [\#569](https://github.com/pypeclub/pype/pull/569) + +**Closed issues:** + +- Nuke Gizmo publishing [\#597](https://github.com/pypeclub/pype/issues/597) +- nuke gizmo publishing error [\#592](https://github.com/pypeclub/pype/issues/592) +- Publish EDL [\#579](https://github.com/pypeclub/pype/issues/579) +- Publish render from SP [\#576](https://github.com/pypeclub/pype/issues/576) +- rename ftrack custom attribute group to `pype` [\#184](https://github.com/pypeclub/pype/issues/184) + +**Merged pull requests:** + +- Audio file existence check [\#614](https://github.com/pypeclub/pype/pull/614) +- NKS small fixes [\#587](https://github.com/pypeclub/pype/pull/587) +- Standalone publisher editorial plugins interfering [\#580](https://github.com/pypeclub/pype/pull/580) + +## [2.12.2](https://github.com/pypeclub/pype/tree/2.12.2) (2020-09-25) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.12.1...2.12.2) + +**Enhancements:** + +- pype config GUI [\#241](https://github.com/pypeclub/pype/issues/241) + +**Fixed bugs:** + +- Harmony: Saving heavy scenes will crash [\#507](https://github.com/pypeclub/pype/issues/507) +- Extract review a representation name with `\*\_burnin` [\#388](https://github.com/pypeclub/pype/issues/388) +- Hierarchy data was not considering active isntances [\#551](https://github.com/pypeclub/pype/pull/551) + +## [2.12.1](https://github.com/pypeclub/pype/tree/2.12.1) (2020-09-15) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.12.0...2.12.1) + +**Fixed bugs:** + +- Pype: changelog.md is outdated [\#503](https://github.com/pypeclub/pype/issues/503) +- dependency security alert ! [\#484](https://github.com/pypeclub/pype/issues/484) +- Maya: RenderSetup is missing update [\#106](https://github.com/pypeclub/pype/issues/106) +- \ extract effects creates new instance [\#78](https://github.com/pypeclub/pype/issues/78) + +## [2.12.0](https://github.com/pypeclub/pype/tree/2.12.0) (2020-09-10) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.11.8...2.12.0) + +**Enhancements:** + +- Less mongo connections [\#509](https://github.com/pypeclub/pype/pull/509) +- Nuke: adding image loader [\#499](https://github.com/pypeclub/pype/pull/499) +- Move launcher window to top if launcher action is clicked [\#450](https://github.com/pypeclub/pype/pull/450) +- Maya: better tile rendering support in Pype [\#446](https://github.com/pypeclub/pype/pull/446) +- Implementation of non QML launcher [\#443](https://github.com/pypeclub/pype/pull/443) +- Optional skip review on renders. [\#441](https://github.com/pypeclub/pype/pull/441) +- Ftrack: Option to push status from task to latest version [\#440](https://github.com/pypeclub/pype/pull/440) +- Properly containerize image plane loads. [\#434](https://github.com/pypeclub/pype/pull/434) +- Option to keep the review files. [\#426](https://github.com/pypeclub/pype/pull/426) +- Isolate view on instance members. [\#425](https://github.com/pypeclub/pype/pull/425) +- Maya: Publishing of tile renderings on Deadline [\#398](https://github.com/pypeclub/pype/pull/398) +- Feature/little bit better logging gui [\#383](https://github.com/pypeclub/pype/pull/383) + +**Fixed bugs:** + +- Maya: Fix tile order for Draft Tile Assembler [\#511](https://github.com/pypeclub/pype/pull/511) +- Remove extra dash [\#501](https://github.com/pypeclub/pype/pull/501) +- Fix: strip dot from repre names in single frame renders [\#498](https://github.com/pypeclub/pype/pull/498) +- Better handling of destination during integrating [\#485](https://github.com/pypeclub/pype/pull/485) +- Fix: allow thumbnail creation for single frame renders [\#460](https://github.com/pypeclub/pype/pull/460) +- added missing argument to launch\_application in ftrack app handler [\#453](https://github.com/pypeclub/pype/pull/453) +- Burnins: Copy bit rate of input video to match quality. [\#448](https://github.com/pypeclub/pype/pull/448) +- Standalone publisher is now independent from tray [\#442](https://github.com/pypeclub/pype/pull/442) +- Bugfix/empty enumerator attributes [\#436](https://github.com/pypeclub/pype/pull/436) +- Fixed wrong order of "other" category collapssing in publisher [\#435](https://github.com/pypeclub/pype/pull/435) +- Multiple reviews where being overwritten to one. [\#424](https://github.com/pypeclub/pype/pull/424) +- Cleanup plugin fail on instances without staging dir [\#420](https://github.com/pypeclub/pype/pull/420) +- deprecated -intra parameter in ffmpeg to new `-g` [\#417](https://github.com/pypeclub/pype/pull/417) +- Delivery action can now work with entered path [\#397](https://github.com/pypeclub/pype/pull/397) + +**Merged pull requests:** + +- Review on instance.data [\#473](https://github.com/pypeclub/pype/pull/473) + +## [2.11.8](https://github.com/pypeclub/pype/tree/2.11.8) (2020-08-27) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.11.7...2.11.8) + +**Enhancements:** + +- DWAA support for Maya [\#382](https://github.com/pypeclub/pype/issues/382) +- Isolate View on Playblast [\#367](https://github.com/pypeclub/pype/issues/367) +- Maya: Tile rendering [\#297](https://github.com/pypeclub/pype/issues/297) +- single pype instance running [\#47](https://github.com/pypeclub/pype/issues/47) +- PYPE-649: projects don't guarantee backwards compatible environment [\#8](https://github.com/pypeclub/pype/issues/8) +- PYPE-663: separate venv for each deployed version [\#7](https://github.com/pypeclub/pype/issues/7) + +**Fixed bugs:** + +- pyblish pype - other group is collapsed before plugins are done [\#431](https://github.com/pypeclub/pype/issues/431) +- Alpha white edges in harmony on PNGs [\#412](https://github.com/pypeclub/pype/issues/412) +- harmony image loader picks wrong representations [\#404](https://github.com/pypeclub/pype/issues/404) +- Clockify crash when response contain symbol not allowed by UTF-8 [\#81](https://github.com/pypeclub/pype/issues/81) + +## [2.11.7](https://github.com/pypeclub/pype/tree/2.11.7) (2020-08-21) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.11.6...2.11.7) + +**Fixed bugs:** + +- Clean Up Baked Movie [\#369](https://github.com/pypeclub/pype/issues/369) +- celaction last workfile [\#459](https://github.com/pypeclub/pype/pull/459) + +## [2.11.6](https://github.com/pypeclub/pype/tree/2.11.6) (2020-08-18) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.11.5...2.11.6) + +**Enhancements:** + +- publisher app [\#56](https://github.com/pypeclub/pype/issues/56) + +## [2.11.5](https://github.com/pypeclub/pype/tree/2.11.5) (2020-08-13) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.11.4...2.11.5) + +**Enhancements:** + +- Switch from master to equivalent [\#220](https://github.com/pypeclub/pype/issues/220) +- Standalone publisher now only groups sequence if the extension is known [\#439](https://github.com/pypeclub/pype/pull/439) + +**Fixed bugs:** + +- Logs have been disable for editorial by default to speed up publishing [\#433](https://github.com/pypeclub/pype/pull/433) +- additional fixes for celaction [\#430](https://github.com/pypeclub/pype/pull/430) +- Harmony: invalid variable scope in validate scene settings [\#428](https://github.com/pypeclub/pype/pull/428) +- new representation name for audio was not accepted [\#427](https://github.com/pypeclub/pype/pull/427) + +## [2.11.4](https://github.com/pypeclub/pype/tree/2.11.4) (2020-08-10) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.11.3...2.11.4) + +**Enhancements:** + +- WebSocket server [\#135](https://github.com/pypeclub/pype/issues/135) +- standalonepublisher: editorial family features expansion \[master branch\] [\#411](https://github.com/pypeclub/pype/pull/411) + +## [2.11.3](https://github.com/pypeclub/pype/tree/2.11.3) (2020-08-04) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.11.2...2.11.3) + +**Fixed bugs:** + +- Harmony: publishing performance issues [\#408](https://github.com/pypeclub/pype/pull/408) + +## [2.11.2](https://github.com/pypeclub/pype/tree/2.11.2) (2020-07-31) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.11.1...2.11.2) + +**Fixed bugs:** + +- Ftrack to Avalon bug [\#406](https://github.com/pypeclub/pype/issues/406) + +## [2.11.1](https://github.com/pypeclub/pype/tree/2.11.1) (2020-07-29) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.11.0...2.11.1) + +**Merged pull requests:** + +- Celaction: metadata json folder fixes on path [\#393](https://github.com/pypeclub/pype/pull/393) +- CelAction - version up method taken fro pype.lib [\#391](https://github.com/pypeclub/pype/pull/391) + ## 2.11.0 ## @@ -430,3 +787,6 @@ A large cleanup release. Most of the change are under the hood. - work directory was sometimes not being created correctly - major pype.lib cleanup. Removing of unused functions, merging those that were doing the same and general house cleaning. - _(avalon)_ subsets in maya 2019 weren't behaving correctly in the outliner + + +\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* From 5f90dea9e5fb4f36fa5f1a80d8934c8cf2a397eb Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Tue, 24 Nov 2020 00:04:39 +0100 Subject: [PATCH 002/279] update changelog config --- .github_changelog_generator | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github_changelog_generator b/.github_changelog_generator index da6c35cebf..ac934ff84f 100644 --- a/.github_changelog_generator +++ b/.github_changelog_generator @@ -2,7 +2,8 @@ pr-wo-labels=False exclude-labels=duplicate,question,invalid,wontfix,weekly-digest author=False unreleased=True -since-tag=2.11.0 +since-tag=2.13.6 release-branch=master enhancement-label=**Enhancements:** issues=False +pulls=False From b29362411e2576fb8d871e2d750641ed491a11f5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 14:32:12 +0100 Subject: [PATCH 003/279] add on/off to env value to bool --- pype/lib/env_tools.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/lib/env_tools.py b/pype/lib/env_tools.py index f31426103b..a5176b814d 100644 --- a/pype/lib/env_tools.py +++ b/pype/lib/env_tools.py @@ -20,9 +20,9 @@ def env_value_to_bool(env_key=None, value=None, default=False): if value is not None: value = str(value).lower() - if value in ("true", "yes", "1"): + if value in ("true", "yes", "1", "on"): return True - elif value in ("false", "no", "0"): + elif value in ("false", "no", "0", "off"): return False return default From 2164dbe6c18a7d9dccfaec79905e1232103dbf14 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 14:33:08 +0100 Subject: [PATCH 004/279] added to lib python functions for work with python modules and classes --- pype/lib/__init__.py | 10 ++++ pype/lib/python_module_tools.py | 101 ++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 pype/lib/python_module_tools.py diff --git a/pype/lib/__init__.py b/pype/lib/__init__.py index 188dd68039..426a5802c3 100644 --- a/pype/lib/__init__.py +++ b/pype/lib/__init__.py @@ -11,6 +11,12 @@ from .env_tools import ( get_paths_from_environ ) +from .python_module_tools import ( + modules_from_path, + recursive_bases_from_class, + classes_from_module +) + from .avalon_context import ( is_latest, any_outdated, @@ -53,6 +59,10 @@ __all__ = [ "env_value_to_bool", "get_paths_from_environ", + "modules_from_path", + "recursive_bases_from_class", + "classes_from_module", + "is_latest", "any_outdated", "get_asset", diff --git a/pype/lib/python_module_tools.py b/pype/lib/python_module_tools.py new file mode 100644 index 0000000000..61a3b1b09e --- /dev/null +++ b/pype/lib/python_module_tools.py @@ -0,0 +1,101 @@ +import os +import types +import inspect +import logging + +log = logging.getLogger(__name__) + + +def modules_from_path(folder_path): + """Get python scripts as modules from a path. + + Arguments: + path (str): Path to folder containing python scripts. + + Returns: + List of modules. + """ + + folder_path = os.path.normpath(folder_path) + + modules = [] + if not os.path.isdir(folder_path): + log.warning("Not a directory path: {}".format(folder_path)) + return modules + + for filename in os.listdir(folder_path): + # Ignore files which start with underscore + if filename.startswith("_"): + continue + + mod_name, mod_ext = os.path.splitext(filename) + if not mod_ext == ".py": + continue + + full_path = os.path.join(folder_path, filename) + if not os.path.isfile(full_path): + continue + + try: + # Prepare module object where content of file will be parsed + module = types.ModuleType(mod_name) + module.__file__ = full_path + + with open(full_path) as _stream: + # Execute content and store it to module object + exec(_stream.read(), module.__dict__) + + modules.append(module) + + except Exception: + log.warning( + "Failed to load path: \"{0}\"".format(full_path), + exc_info=True + ) + continue + + return modules + + +def recursive_bases_from_class(klass): + """Extract all bases from entered class.""" + result = [] + bases = klass.__bases__ + result.extend(bases) + for base in bases: + result.extend(recursive_bases_from_class(base)) + return result + + +def classes_from_module(superclass, module): + """Return plug-ins from module + + Arguments: + superclass (superclass): Superclass of subclasses to look for + module (types.ModuleType): Imported module from which to + parse valid Avalon plug-ins. + + Returns: + List of plug-ins, or empty list if none is found. + + """ + + classes = list() + for name in dir(module): + # It could be anything at this point + obj = getattr(module, name) + if not inspect.isclass(obj): + continue + + # These are subclassed from nothing, not even `object` + if not len(obj.__bases__) > 0: + continue + + # Use string comparison rather than `issubclass` + # in order to support reloading of this module. + bases = recursive_bases_from_class(obj) + if not any(base.__name__ == superclass.__name__ for base in bases): + continue + + classes.append(obj) + return classes From a3afd0b5cffe739136dec376aa574cc8846450e3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 14:33:56 +0100 Subject: [PATCH 005/279] applications has new class LaunchHook similar to PypeHook --- pype/lib/applications.py | 68 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/pype/lib/applications.py b/pype/lib/applications.py index 600530a00f..8653e77da1 100644 --- a/pype/lib/applications.py +++ b/pype/lib/applications.py @@ -713,6 +713,74 @@ class Application: return self.manager.launch(self.app_name, *args, **kwargs) +@six.add_metaclass(ABCMeta) +class LaunchHook: + """Abstract class from all hooks should inherit.""" + # Order of prelaunch hook, will be executed as last if set to None. + order = None + # If hook should be executed befor or after application launch + prelaunch = True + # List of host implementations, skipped if empty. + hosts = [] + # List of platform availability, skipped if empty. + platforms = [] + + def __init__(self, launch_context): + """Constructor of launch hook. + + Always should be called + """ + self.log = logging.getLogger(self.__class__.__name__) + + self.launch_context = launch_context + + is_valid = self.class_validation(launch_context) + if is_valid: + is_valid = self.validate() + + self.is_valid = is_valid + + @classmethod + def class_validation(cls, launch_context): + """Validation of class attributes by launch context. + + Args: + launch_context (ApplicationLaunchContext): Context of launching + application. + + Returns: + bool: Is launch hook valid for the context by class attributes. + """ + if cls.platforms: + low_platforms = tuple( + _platform.lower() + for _platform in cls.platforms + ) + if platform.system().lower() not in low_platforms: + return False + + if cls.hosts: + if launch_context.host_name not in cls.hosts: + return False + + return True + + def validate(self): + """Optional validation of launch hook on initialization. + + Returns: + bool: Hook is valid (True) or invalid (False). + """ + # QUESTION Not sure if this method has any usable potential. + # - maybe result can be based on settings + return True + + @abstractmethod + def execute(self, *args, **kwargs): + """Abstract execute method where logic of hook is.""" + pass + + class ApplicationLaunchContext: """Context of launching application. From 52ff856bb65824c280a29fb5c4351f652f6142a2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 14:34:30 +0100 Subject: [PATCH 006/279] application context has method to load launch hooks --- pype/lib/applications.py | 75 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/pype/lib/applications.py b/pype/lib/applications.py index 8653e77da1..0a6f7b481f 100644 --- a/pype/lib/applications.py +++ b/pype/lib/applications.py @@ -5,9 +5,12 @@ import getpass import json import copy import platform +import inspect import logging import subprocess +from abc import ABCMeta, abstractmethod +import six import acre import avalon.lib @@ -853,6 +856,78 @@ class ApplicationLaunchContext: self.prepare_host_environments() self.prepare_context_environments() + def paths_to_launch_hook(self): + """Directory paths where to look for launch hooks.""" + # This method has potential to be part of application manager (maybe). + paths = [] + + return paths + + def discover_launch_hooks(self): + classes = [] + paths = self.paths_to_launch_hook() + for path in paths: + if not os.path.exists(path): + self.log.info( + "Path to launch hooks does not exists: \"{}\"".format(path) + ) + continue + + modules = modules_from_path(path) + for _module in modules: + classes.extend(classes_from_module(LaunchHook, _module)) + + pre_hooks_with_order = [] + pre_hooks_without_order = [] + post_hooks_with_order = [] + post_hooks_without_order = [] + for klass in classes: + try: + hook = klass(self) + if not hook.is_valid: + self.log.debug( + "Hook is not valid for curent launch context." + ) + continue + + if inspect.isabstract(hook): + self.log.debug("Skipped abstract hook: {}".format( + str(hook) + )) + continue + + # Separate hooks if should be executed before or after launch + if hook.prelaunch: + if hook.order is None: + pre_hooks_without_order.append(hook) + else: + pre_hooks_with_order.append(hook) + else: + if hook.order is None: + post_hooks_with_order.append(hook) + else: + post_hooks_without_order.append(hook) + + except Exception: + self.log.warning( + "Initialization of hook failed. {}".format(str(klass)), + exc_info=True + ) + + # Sort hooks with order by order + pre_hooks_ordered = list(sorted( + pre_hooks_with_order, key=lambda obj: obj.order + )) + post_hooks_ordered = list(sorted( + post_hooks_with_order, key=lambda obj: obj.order + )) + + # Extend ordered hooks with hooks without defined order + pre_hooks_ordered.extend(pre_hooks_without_order) + post_hooks_ordered.extend(post_hooks_without_order) + + return pre_hooks_ordered, post_hooks_ordered + @property def app_name(self): return self.application.app_name From 17b05915870d8673ed228d2782e48d5b8879b992 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 14:43:28 +0100 Subject: [PATCH 007/279] added base of getting hooks dir paths --- pype/lib/applications.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/pype/lib/applications.py b/pype/lib/applications.py index 0a6f7b481f..b17b1fdbb0 100644 --- a/pype/lib/applications.py +++ b/pype/lib/applications.py @@ -23,6 +23,10 @@ from ..api import ( system_settings, environments ) +from .python_module_tools import ( + modules_from_path, + classes_from_module +) from .hooks import execute_hook from .deprecated import get_avalon_database from .env_tools import env_value_to_bool @@ -856,16 +860,28 @@ class ApplicationLaunchContext: self.prepare_host_environments() self.prepare_context_environments() - def paths_to_launch_hook(self): + def paths_to_launch_hooks(self): """Directory paths where to look for launch hooks.""" # This method has potential to be part of application manager (maybe). + + # TODO find better way how to define dir path to default launch hooks + import pype + pype_dir = os.path.dirname(os.path.abspath(pype.__file__)) + hooks_dir = os.path.join(pype_dir, "hooks") + + # TODO load additional studio paths from settings + # TODO add paths based on used modules (like `ftrack`) paths = [] - + subfolder_names = ["global", self.host_name, self.app_name] + for subfolder_name in subfolder_names: + path = os.path.join(hooks_dir, subfolder_name) + if os.path.exists(path) and os.path.isdir(path): + paths.append(path) return paths def discover_launch_hooks(self): classes = [] - paths = self.paths_to_launch_hook() + paths = self.paths_to_launch_hooks() for path in paths: if not os.path.exists(path): self.log.info( From e545a6798aa513818a370bb97d86d29a1fd0d63b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 14:46:22 +0100 Subject: [PATCH 008/279] prelaunch and post launch hooks are discovered and executed --- pype/lib/applications.py | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/pype/lib/applications.py b/pype/lib/applications.py index b17b1fdbb0..b135db8057 100644 --- a/pype/lib/applications.py +++ b/pype/lib/applications.py @@ -968,20 +968,31 @@ class ApplicationLaunchContext: self.log.warning("Application was already launched.") return + # Discover launch hooks + prelaunch_hooks, postlaunch_hooks = self.discover_launch_hooks() + + # Execute prelaunch hooks + for prelaunch_hook in prelaunch_hooks: + prelaunch_hook.execute() + + # Prepare subprocess args args = self.clear_launch_args(self.launch_args) self.log.debug( "Launching \"{}\" with args: {}".format(self.app_name, args) ) + # Run process self.process = subprocess.Popen(args, **self.kwargs) - # TODO do this with after-launch hooks - try: - self.after_launch_procedures() - except Exception: - self.log.warning( - "After launch procedures were not successful.", - exc_info=True - ) + # Process post launch hooks + for postlaunch_hook in postlaunch_hooks: + try: + postlaunch_hook.execute() + + except Exception: + self.log.warning( + "After launch procedures were not successful.", + exc_info=True + ) return self.process From 0dc51f3d6d7fe05823c17eb0dfdef5f8cdd43648 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 14:51:32 +0100 Subject: [PATCH 009/279] hooks are launch hooks are stored to launch context --- pype/lib/applications.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/pype/lib/applications.py b/pype/lib/applications.py index b135db8057..5aca9ac90b 100644 --- a/pype/lib/applications.py +++ b/pype/lib/applications.py @@ -853,6 +853,9 @@ class ApplicationLaunchContext: ) self.kwargs["creationflags"] = flags + self.prelaunch_hooks = None + self.postlaunch_hooks = None + self.process = None # TODO move these to pre-paunch hook @@ -879,7 +882,18 @@ class ApplicationLaunchContext: paths.append(path) return paths - def discover_launch_hooks(self): + def discover_launch_hooks(self, force=False): + if ( + self.prelaunch_hooks is not None + or self.postlaunch_hooks is not None + ): + if not force: + self.log.info("Launch hooks were already discovered.") + return + + self.prelaunch_hooks.clear() + self.postlaunch_hooks.clear() + classes = [] paths = self.paths_to_launch_hooks() for path in paths: @@ -942,7 +956,8 @@ class ApplicationLaunchContext: pre_hooks_ordered.extend(pre_hooks_without_order) post_hooks_ordered.extend(post_hooks_without_order) - return pre_hooks_ordered, post_hooks_ordered + self.prelaunch_hooks = pre_hooks_ordered + self.postlaunch_hooks = post_hooks_ordered @property def app_name(self): @@ -969,10 +984,10 @@ class ApplicationLaunchContext: return # Discover launch hooks - prelaunch_hooks, postlaunch_hooks = self.discover_launch_hooks() + self.discover_launch_hooks() # Execute prelaunch hooks - for prelaunch_hook in prelaunch_hooks: + for prelaunch_hook in self.prelaunch_hooks: prelaunch_hook.execute() # Prepare subprocess args @@ -984,7 +999,7 @@ class ApplicationLaunchContext: self.process = subprocess.Popen(args, **self.kwargs) # Process post launch hooks - for postlaunch_hook in postlaunch_hooks: + for postlaunch_hook in self.postlaunch_hooks: try: postlaunch_hook.execute() From 97c46f79c9134e7942c914e40f40a0d71665a63c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 15:41:19 +0100 Subject: [PATCH 010/279] few small changes --- pype/lib/__init__.py | 2 ++ pype/lib/applications.py | 3 +++ 2 files changed, 5 insertions(+) diff --git a/pype/lib/__init__.py b/pype/lib/__init__.py index 426a5802c3..512cb12e37 100644 --- a/pype/lib/__init__.py +++ b/pype/lib/__init__.py @@ -34,6 +34,7 @@ from .applications import ( ApplictionExecutableNotFound, ApplicationNotFound, ApplicationManager, + LaunchHook, launch_application, ApplicationAction, _subprocess @@ -78,6 +79,7 @@ __all__ = [ "ApplictionExecutableNotFound", "ApplicationNotFound", "ApplicationManager", + "LaunchHook", "launch_application", "ApplicationAction", diff --git a/pype/lib/applications.py b/pype/lib/applications.py index 5aca9ac90b..ca80676cba 100644 --- a/pype/lib/applications.py +++ b/pype/lib/applications.py @@ -883,6 +883,7 @@ class ApplicationLaunchContext: return paths def discover_launch_hooks(self, force=False): + """Load and prepare launch hooks.""" if ( self.prelaunch_hooks is not None or self.postlaunch_hooks is not None @@ -1000,6 +1001,8 @@ class ApplicationLaunchContext: # Process post launch hooks for postlaunch_hook in self.postlaunch_hooks: + # TODO how to handle errors? + # - store to variable to let them accesible? try: postlaunch_hook.execute() From 3de491d487ee54141934d3378fedc6e84e19a7d8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 15:53:03 +0100 Subject: [PATCH 011/279] collect ftrack api module to context --- pype/plugins/ftrack/publish/collect_ftrack_api.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pype/plugins/ftrack/publish/collect_ftrack_api.py b/pype/plugins/ftrack/publish/collect_ftrack_api.py index bbda6da3b0..59839d7710 100644 --- a/pype/plugins/ftrack/publish/collect_ftrack_api.py +++ b/pype/plugins/ftrack/publish/collect_ftrack_api.py @@ -96,6 +96,7 @@ class CollectFtrackApi(pyblish.api.ContextPlugin): task_entity = None self.log.warning("Task name is not set.") + context.data["ftrackPythonModule"] = ftrack_api context.data["ftrackProject"] = project_entity context.data["ftrackEntity"] = asset_entity context.data["ftrackTask"] = task_entity From 3f869f20bb26168b7a9baf3b26a09be8c78e8956 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 15:53:38 +0100 Subject: [PATCH 012/279] removed backwards compatibility and added `get_pype_attr` to imports --- pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py index e4496138bb..0e28fd1fe5 100644 --- a/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py +++ b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py @@ -3,10 +3,10 @@ import six import pyblish.api from avalon import io -try: - from pype.modules.ftrack.lib.avalon_sync import CUST_ATTR_AUTO_SYNC -except Exception: - CUST_ATTR_AUTO_SYNC = "avalon_auto_sync" +from pype.modules.ftrack.lib.avalon_sync import ( + CUST_ATTR_AUTO_SYNC, + get_pype_attr +) class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): From 4ffda1a6466f2ff1932d98d2cb61049feec33fb5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 15:54:01 +0100 Subject: [PATCH 013/279] prepare hiearchical custom attributes definitions before import --- .../plugins/ftrack/publish/integrate_hierarchy_ftrack.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py index 0e28fd1fe5..c274669f55 100644 --- a/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py +++ b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py @@ -73,6 +73,15 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): self.auto_sync_on(project) def import_to_ftrack(self, input_data, parent=None): + # Prequery hiearchical custom attributes + hier_custom_attributes = get_pype_attr(self.session)[1] + hier_attr_by_key = { + attr["key"]: attr + for attr in hier_custom_attributes + } + # Get ftrack api module (as they are different per python version) + ftrack_api = self.context.data["ftrackPythonModule"] + for entity_name in input_data: entity_data = input_data[entity_name] entity_type = entity_data['entity_type'] From 0a659548e9ad0206df7dd13aa1640891eeccc6fd Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 15:54:29 +0100 Subject: [PATCH 014/279] use ftrack operations to set custom attribute value if key is hierarchical --- .../publish/integrate_hierarchy_ftrack.py | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py index c274669f55..ef8ee9a216 100644 --- a/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py +++ b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py @@ -1,5 +1,6 @@ import sys import six +import collections import pyblish.api from avalon import io @@ -124,12 +125,34 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): i for i in self.context if i.data['asset'] in entity['name'] ] for key in custom_attributes: - assert (key in entity['custom_attributes']), ( - 'Missing custom attribute key: `{0}` in attrs: ' - '`{1}`'.format(key, entity['custom_attributes'].keys()) - ) + hier_attr = hier_attr_by_key.get(key) + # Use simple method if key is not hierarchical + if not hier_attr: + assert (key in entity['custom_attributes']), ( + 'Missing custom attribute key: `{0}` in attrs: ' + '`{1}`'.format(key, entity['custom_attributes'].keys()) + ) - entity['custom_attributes'][key] = custom_attributes[key] + entity['custom_attributes'][key] = custom_attributes[key] + + else: + # Use ftrack operations method to set hiearchical + # attribute value. + # - this is because there may be non hiearchical custom + # attributes with different properties + entity_key = collections.OrderedDict({ + "configuration_id": hier_attr["id"], + "entity_id": entity["id"] + }) + self.session.recorded_operations.push( + ftrack_api.operation.UpdateEntityOperation( + "ContextCustomAttributeValue", + entity_key, + "value", + ftrack_api.symbol.NOT_SET, + custom_attributes[key] + ) + ) for instance in instances: instance.data['ftrackEntity'] = entity From 687ccf7217cea94fae380af0453ededb7afb7887 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 17:05:20 +0100 Subject: [PATCH 015/279] env attribute directly points to kwargs --- pype/lib/applications.py | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/pype/lib/applications.py b/pype/lib/applications.py index ca80676cba..ed21a1b7e5 100644 --- a/pype/lib/applications.py +++ b/pype/lib/applications.py @@ -824,14 +824,6 @@ class ApplicationLaunchContext: self.data = dict(data) - # Handle launch environemtns - passed_env = self.data.pop("env", None) - if passed_env is None: - env = os.environ - else: - env = passed_env - self.env = copy.deepcopy(env) - # Load settings if were not passed in data settings_env = self.data.get("settings_env") if settings_env is None: @@ -840,9 +832,17 @@ class ApplicationLaunchContext: # subprocess.Popen launch arguments (first argument in constructor) self.launch_args = [executable] + + # Handle launch environemtns + passed_env = self.data.pop("env", None) + if passed_env is None: + env = os.environ + else: + env = passed_env + # subprocess.Popen keyword arguments self.kwargs = { - "env": self.env + "env": copy.deepcopy(env) } if platform.system().lower() == "windows": @@ -862,6 +862,24 @@ class ApplicationLaunchContext: self.prepare_global_data() self.prepare_host_environments() self.prepare_context_environments() + @property + def env(self): + if ( + "env" not in self.kwargs + or self.kwargs["env"] is None + ): + self.kwargs["env"] = {} + return self.kwargs["env"] + + @env.setter + def env(self, value): + if not isinstance(value, dict): + raise ValueError( + "'env' attribute expect 'dict' object. Got: {}".format( + str(type(value)) + ) + ) + self.kwargs["env"] = value def paths_to_launch_hooks(self): """Directory paths where to look for launch hooks.""" From 9a814320ba6952025fce0c2215214b2792e33432 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 17:05:46 +0100 Subject: [PATCH 016/279] LaunchHook is using PypeLogger --- pype/lib/applications.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/lib/applications.py b/pype/lib/applications.py index ed21a1b7e5..80b698ecc8 100644 --- a/pype/lib/applications.py +++ b/pype/lib/applications.py @@ -737,7 +737,7 @@ class LaunchHook: Always should be called """ - self.log = logging.getLogger(self.__class__.__name__) + self.log = Logger().get_logger(self.__class__.__name__) self.launch_context = launch_context From baa10c6eb50fca4e5c61993774eed7857348e92b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 17:06:47 +0100 Subject: [PATCH 017/279] LaunchHook has few wrapped attributes --- pype/lib/applications.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/pype/lib/applications.py b/pype/lib/applications.py index 80b698ecc8..675b0c90be 100644 --- a/pype/lib/applications.py +++ b/pype/lib/applications.py @@ -772,6 +772,26 @@ class LaunchHook: return True + @property + def data(self): + return self.launch_context.data + + @property + def application(self): + return getattr(self.launch_context, "application", None) + + @property + def manager(self): + return getattr(self.application, "manager", None) + + @property + def host_name(self): + return getattr(self.application, "host_name", None) + + @property + def app_name(self): + return getattr(self.application, "app_name", None) + def validate(self): """Optional validation of launch hook on initialization. From e24ff6725a5ecc11df6d02d7f73e966b6752566b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 17:07:17 +0100 Subject: [PATCH 018/279] created global host launch hook --- pype/hooks/global/global_host_data.py | 366 ++++++++++++++++++++++++++ pype/lib/applications.py | 347 ++---------------------- 2 files changed, 384 insertions(+), 329 deletions(-) create mode 100644 pype/hooks/global/global_host_data.py diff --git a/pype/hooks/global/global_host_data.py b/pype/hooks/global/global_host_data.py new file mode 100644 index 0000000000..3f82f3b099 --- /dev/null +++ b/pype/hooks/global/global_host_data.py @@ -0,0 +1,366 @@ +import os +import re +import json +import getpass +import copy + +from pype.api import ( + Anatomy, + config +) +from pype.lib import ( + env_value_to_bool, + LaunchHook, + ApplicationLaunchFailed +) + +import acre +import avalon.api + + +class GlobalHostDataHook(LaunchHook): + order = -100 + + def execute(self): + """Prepare global objects to `data` that will be used for sure.""" + if not self.application.is_host: + self.log.info( + "Skipped hook {}. Application is not marked as host.".format( + self.__class__.__name__ + ) + ) + return + + self.prepare_global_data() + self.prepare_host_environments() + self.prepare_context_environments() + + def prepare_global_data(self): + """Prepare global objects to `data` that will be used for sure.""" + # Mongo documents + project_name = self.launch_context.data.get("project_name") + if not project_name: + self.log.info( + "Skipping global data preparation." + " Key `project_name` was not found in launch context." + ) + return + + self.log.debug("Project name is set to \"{}\"".format(project_name)) + # Anatomy + self.launch_context.data["anatomy"] = Anatomy(project_name) + + # Mongo connection + dbcon = avalon.api.AvalonMongoDB() + dbcon.Session["AVALON_PROJECT"] = project_name + dbcon.install() + + self.launch_context.data["dbcon"] = dbcon + + # Project document + project_doc = dbcon.find_one({"type": "project"}) + self.launch_context.data["project_doc"] = project_doc + + asset_name = self.launch_context.data.get("asset_name") + if not asset_name: + self.log.warning( + "Asset name was not set. Skipping asset document query." + ) + return + + asset_doc = dbcon.find_one({ + "type": "asset", + "name": asset_name + }) + self.launch_context.data["asset_doc"] = asset_doc + + def _merge_env(self, env, current_env): + """Modified function(merge) from acre module.""" + result = current_env.copy() + for key, value in env.items(): + # Keep missing keys by not filling `missing` kwarg + value = acre.lib.partial_format(value, data=current_env) + result[key] = value + return result + + def prepare_host_environments(self): + """Modify launch environments based on launched app and context.""" + # Keys for getting environments + env_keys = [ + self.launch_context.host_name, + self.launch_context.app_name + ] + + asset_doc = self.launch_context.data.get("asset_doc") + if asset_doc: + # Add tools environments + for key in asset_doc["data"].get("tools_env") or []: + tool = self.manager.tools.get(key) + if tool: + if tool.group_name not in env_keys: + env_keys.append(tool.group_name) + + if tool.name not in env_keys: + env_keys.append(tool.name) + + self.log.debug( + "Finding environment groups for keys: {}".format(env_keys) + ) + + settings_env = self.launch_context.data["settings_env"] + env_values = {} + for env_key in env_keys: + _env_values = settings_env.get(env_key) + if not _env_values: + continue + + # Choose right platform + tool_env = acre.parse(_env_values) + # Merge dictionaries + env_values = self._merge_env(tool_env, env_values) + + final_env = self._merge_env( + acre.compute(env_values), self.launch_context.env + ) + + # Update env + self.launch_context.env.update(final_env) + + def prepare_context_environments(self): + """Modify launch environemnts with context data for launched host.""" + # Context environments + project_doc = self.launch_context.data.get("project_doc") + asset_doc = self.launch_context.data.get("asset_doc") + task_name = self.launch_context.data.get("task_name") + if ( + not project_doc + or not asset_doc + or not task_name + ): + self.log.info( + "Skipping context environments preparation." + " Launch context does not contain required data." + ) + return + + workdir_data = self._prepare_workdir_data( + project_doc, asset_doc, task_name + ) + self.launch_context.data["workdir_data"] = workdir_data + + hierarchy = workdir_data["hierarchy"] + anatomy = self.launch_context.data["anatomy"] + + try: + anatomy_filled = anatomy.format(workdir_data) + workdir = os.path.normpath(anatomy_filled["work"]["folder"]) + if not os.path.exists(workdir): + self.log.debug( + "Creating workdir folder: \"{}\"".format(workdir) + ) + os.makedirs(workdir) + + except Exception as exc: + raise ApplicationLaunchFailed( + "Error in anatomy.format: {}".format(str(exc)) + ) + + context_env = { + "AVALON_PROJECT": project_doc["name"], + "AVALON_ASSET": asset_doc["name"], + "AVALON_TASK": task_name, + "AVALON_APP": self.launch_context.host_name, + "AVALON_APP_NAME": self.launch_context.app_name, + "AVALON_HIERARCHY": hierarchy, + "AVALON_WORKDIR": workdir + } + self.log.debug( + "Context environemnts set:\n{}".format( + json.dumps(context_env, indent=4) + ) + ) + self.launch_context.env.update(context_env) + + self.prepare_last_workfile(workdir) + + def _prepare_workdir_data(self, project_doc, asset_doc, task_name): + hierarchy = "/".join(asset_doc["data"]["parents"]) + + data = { + "project": { + "name": project_doc["name"], + "code": project_doc["data"].get("code") + }, + "task": task_name, + "asset": asset_doc["name"], + "app": self.launch_context.host_name, + "hierarchy": hierarchy + } + return data + + def prepare_last_workfile(self, workdir): + """last workfile workflow preparation. + + Function check if should care about last workfile workflow and tries + to find the last workfile. Both information are stored to `data` and + environments. + + Last workfile is filled always (with version 1) even if any workfile + exists yet. + + Args: + workdir (str): Path to folder where workfiles should be stored. + """ + _workdir_data = self.launch_context.data.get("workdir_data") + if not _workdir_data: + self.log.info( + "Skipping last workfile preparation." + " Key `workdir_data` not filled." + ) + return + + workdir_data = copy.deepcopy(_workdir_data) + project_name = self.launch_context.data["project_name"] + task_name = self.launch_context.data["task_name"] + start_last_workfile = self.should_start_last_workfile( + project_name, self.launch_context.host_name, task_name + ) + self.launch_context.data["start_last_workfile"] = start_last_workfile + + # Store boolean as "0"(False) or "1"(True) + self.launch_context.env["AVALON_OPEN_LAST_WORKFILE"] = ( + str(int(bool(start_last_workfile))) + ) + + _sub_msg = "" if start_last_workfile else " not" + self.log.debug( + "Last workfile should{} be opened on start.".format(_sub_msg) + ) + + # Last workfile path + last_workfile_path = "" + extensions = avalon.api.HOST_WORKFILE_EXTENSIONS.get( + self.launch_context.host_name + ) + if extensions: + anatomy = self.launch_context.data["anatomy"] + # Find last workfile + file_template = anatomy.templates["work"]["file"] + workdir_data.update({ + "version": 1, + "user": os.environ.get("PYPE_USERNAME") or getpass.getuser(), + "ext": extensions[0] + }) + + last_workfile_path = avalon.api.last_workfile( + workdir, file_template, workdir_data, extensions, True + ) + + if os.path.exists(last_workfile_path): + self.log.debug(( + "Workfiles for launch context does not exists" + " yet but path will be set." + )) + self.log.debug( + "Setting last workfile path: {}".format(last_workfile_path) + ) + + self.launch_context.env["AVALON_LAST_WORKFILE"] = last_workfile_path + self.launch_context.data["last_workfile_path"] = last_workfile_path + + def should_start_last_workfile(self, project_name, host_name, task_name): + """Define if host should start last version workfile if possible. + + Default output is `False`. Can be overriden with environment variable + `AVALON_OPEN_LAST_WORKFILE`, valid values without case sensitivity are + `"0", "1", "true", "false", "yes", "no"`. + + Args: + project_name (str): Name of project. + host_name (str): Name of host which is launched. In avalon's + application context it's value stored in app definition under + key `"application_dir"`. Is not case sensitive. + task_name (str): Name of task which is used for launching the host. + Task name is not case sensitive. + + Returns: + bool: True if host should start workfile. + + """ + default_output = env_value_to_bool( + "AVALON_OPEN_LAST_WORKFILE", default=False + ) + # TODO convert to settings + try: + startup_presets = ( + config.get_presets(project_name) + .get("tools", {}) + .get("workfiles", {}) + .get("last_workfile_on_startup") + ) + except Exception: + startup_presets = None + self.log.warning("Couldn't load pype's presets", exc_info=True) + + if not startup_presets: + return default_output + + host_name_lowered = host_name.lower() + task_name_lowered = task_name.lower() + + max_points = 2 + matching_points = -1 + matching_item = None + for item in startup_presets: + hosts = item.get("hosts") or tuple() + tasks = item.get("tasks") or tuple() + + hosts_lowered = tuple(_host_name.lower() for _host_name in hosts) + # Skip item if has set hosts and current host is not in + if hosts_lowered and host_name_lowered not in hosts_lowered: + continue + + tasks_lowered = tuple(_task_name.lower() for _task_name in tasks) + # Skip item if has set tasks and current task is not in + if tasks_lowered: + task_match = False + for task_regex in self.compile_list_of_regexes(tasks_lowered): + if re.match(task_regex, task_name_lowered): + task_match = True + break + + if not task_match: + continue + + points = int(bool(hosts_lowered)) + int(bool(tasks_lowered)) + if points > matching_points: + matching_item = item + matching_points = points + + if matching_points == max_points: + break + + if matching_item is not None: + output = matching_item.get("enabled") + if output is None: + output = default_output + return output + return default_output + + @staticmethod + def compile_list_of_regexes(in_list): + """Convert strings in entered list to compiled regex objects.""" + regexes = list() + if not in_list: + return regexes + + for item in in_list: + if item: + try: + regexes.append(re.compile(item)) + except TypeError: + print(( + "Invalid type \"{}\" value \"{}\"." + " Expected string based object. Skipping." + ).format(str(type(item)), str(item))) + return regexes diff --git a/pype/lib/applications.py b/pype/lib/applications.py index 675b0c90be..3804db1ed1 100644 --- a/pype/lib/applications.py +++ b/pype/lib/applications.py @@ -29,7 +29,7 @@ from .python_module_tools import ( ) from .hooks import execute_hook from .deprecated import get_avalon_database -from .env_tools import env_value_to_bool + log = logging.getLogger(__name__) @@ -80,24 +80,6 @@ class ApplicationLaunchFailed(Exception): pass -def compile_list_of_regexes(in_list): - """Convert strings in entered list to compiled regex objects.""" - regexes = list() - if not in_list: - return regexes - - for item in in_list: - if item: - try: - regexes.append(re.compile(item)) - except TypeError: - print(( - "Invalid type \"{}\" value \"{}\"." - " Expected string based object. Skipping." - ).format(str(type(item)), str(item))) - return regexes - - def launch_application(project_name, asset_name, task_name, app_name): """Launch host application with filling required environments. @@ -878,10 +860,6 @@ class ApplicationLaunchContext: self.process = None - # TODO move these to pre-paunch hook - self.prepare_global_data() - self.prepare_host_environments() - self.prepare_context_environments() @property def env(self): if ( @@ -933,8 +911,14 @@ class ApplicationLaunchContext: self.prelaunch_hooks.clear() self.postlaunch_hooks.clear() - classes = [] + self.log.debug("Discovery of launch hooks started.") + paths = self.paths_to_launch_hooks() + self.log.debug("Paths where will look for launch hooks:{}".format( + "\n- ".join(paths) + )) + + classes = [] for path in paths: if not os.path.exists(path): self.log.info( @@ -997,6 +981,9 @@ class ApplicationLaunchContext: self.prelaunch_hooks = pre_hooks_ordered self.postlaunch_hooks = post_hooks_ordered + self.log.debug("Found {} prelaunch and {} postlaunch hooks.".format( + len(self.prelaunch_hooks), len(self.postlaunch_hooks) + )) @property def app_name(self): @@ -1027,6 +1014,9 @@ class ApplicationLaunchContext: # Execute prelaunch hooks for prelaunch_hook in self.prelaunch_hooks: + self.log.debug("Executing prelaunch hook: {}".format( + str(prelaunch_hook) + )) prelaunch_hook.execute() # Prepare subprocess args @@ -1039,6 +1029,10 @@ class ApplicationLaunchContext: # Process post launch hooks for postlaunch_hook in self.postlaunch_hooks: + self.log.debug("Executing postlaunch hook: {}".format( + str(prelaunch_hook) + )) + # TODO how to handle errors? # - store to variable to let them accesible? try: @@ -1087,311 +1081,6 @@ class ApplicationLaunchContext: break return args - def prepare_global_data(self): - """Prepare global objects to `data` that will be used for sure.""" - # Mongo documents - project_name = self.data.get("project_name") - if not project_name: - self.log.info( - "Skipping global data preparation." - " Key `project_name` was not found in launch context." - ) - return - - self.log.debug("Project name is set to \"{}\"".format(project_name)) - # Anatomy - self.data["anatomy"] = Anatomy(project_name) - - # Mongo connection - dbcon = avalon.api.AvalonMongoDB() - dbcon.Session["AVALON_PROJECT"] = project_name - dbcon.install() - - self.data["dbcon"] = dbcon - - # Project document - project_doc = dbcon.find_one({"type": "project"}) - self.data["project_doc"] = project_doc - - asset_name = self.data.get("asset_name") - if not asset_name: - self.log.warning( - "Asset name was not set. Skipping asset document query." - ) - return - - asset_doc = dbcon.find_one({ - "type": "asset", - "name": asset_name - }) - self.data["asset_doc"] = asset_doc - - def _merge_env(self, env, current_env): - """Modified function(merge) from acre module.""" - result = current_env.copy() - for key, value in env.items(): - # Keep missing keys by not filling `missing` kwarg - value = acre.lib.partial_format(value, data=current_env) - result[key] = value - return result - - def prepare_host_environments(self): - """Modify launch environments based on launched app and context.""" - # Keys for getting environments - env_keys = [self.host_name, self.app_name] - - asset_doc = self.data.get("asset_doc") - if asset_doc: - # Add tools environments - for key in asset_doc["data"].get("tools_env") or []: - tool = self.manager.tools.get(key) - if tool: - if tool.group_name not in env_keys: - env_keys.append(tool.group_name) - - if tool.name not in env_keys: - env_keys.append(tool.name) - - self.log.debug( - "Finding environment groups for keys: {}".format(env_keys) - ) - - settings_env = self.data["settings_env"] - env_values = {} - for env_key in env_keys: - _env_values = settings_env.get(env_key) - if not _env_values: - continue - - # Choose right platform - tool_env = acre.parse(_env_values) - # Merge dictionaries - env_values = self._merge_env(tool_env, env_values) - - final_env = self._merge_env(acre.compute(env_values), self.env) - - # Update env - self.env.update(final_env) - - def prepare_context_environments(self): - """Modify launch environemnts with context data for launched host.""" - # Context environments - project_doc = self.data.get("project_doc") - asset_doc = self.data.get("asset_doc") - task_name = self.data.get("task_name") - if ( - not project_doc - or not asset_doc - or not task_name - ): - self.log.info( - "Skipping context environments preparation." - " Launch context does not contain required data." - ) - return - - workdir_data = self._prepare_workdir_data( - project_doc, asset_doc, task_name - ) - self.data["workdir_data"] = workdir_data - - hierarchy = workdir_data["hierarchy"] - anatomy = self.data["anatomy"] - - try: - anatomy_filled = anatomy.format(workdir_data) - workdir = os.path.normpath(anatomy_filled["work"]["folder"]) - if not os.path.exists(workdir): - self.log.debug( - "Creating workdir folder: \"{}\"".format(workdir) - ) - os.makedirs(workdir) - - except Exception as exc: - raise ApplicationLaunchFailed( - "Error in anatomy.format: {}".format(str(exc)) - ) - - context_env = { - "AVALON_PROJECT": project_doc["name"], - "AVALON_ASSET": asset_doc["name"], - "AVALON_TASK": task_name, - "AVALON_APP": self.host_name, - "AVALON_APP_NAME": self.app_name, - "AVALON_HIERARCHY": hierarchy, - "AVALON_WORKDIR": workdir - } - self.log.debug( - "Context environemnts set:\n{}".format( - json.dumps(context_env, indent=4) - ) - ) - self.env.update(context_env) - - self.prepare_last_workfile(workdir) - - def _prepare_workdir_data(self, project_doc, asset_doc, task_name): - hierarchy = "/".join(asset_doc["data"]["parents"]) - - data = { - "project": { - "name": project_doc["name"], - "code": project_doc["data"].get("code") - }, - "task": task_name, - "asset": asset_doc["name"], - "app": self.host_name, - "hierarchy": hierarchy - } - return data - - def prepare_last_workfile(self, workdir): - """last workfile workflow preparation. - - Function check if should care about last workfile workflow and tries - to find the last workfile. Both information are stored to `data` and - environments. - - Last workfile is filled always (with version 1) even if any workfile - exists yet. - - Args: - workdir (str): Path to folder where workfiles should be stored. - """ - _workdir_data = self.data.get("workdir_data") - if not _workdir_data: - self.log.info( - "Skipping last workfile preparation." - " Key `workdir_data` not filled." - ) - return - - workdir_data = copy.deepcopy(_workdir_data) - project_name = self.data["project_name"] - task_name = self.data["task_name"] - start_last_workfile = self.should_start_last_workfile( - project_name, self.host_name, task_name - ) - self.data["start_last_workfile"] = start_last_workfile - - # Store boolean as "0"(False) or "1"(True) - self.env["AVALON_OPEN_LAST_WORKFILE"] = ( - str(int(bool(start_last_workfile))) - ) - - _sub_msg = "" if start_last_workfile else " not" - self.log.debug( - "Last workfile should{} be opened on start.".format(_sub_msg) - ) - - # Last workfile path - last_workfile_path = "" - extensions = avalon.api.HOST_WORKFILE_EXTENSIONS.get(self.host_name) - if extensions: - anatomy = self.data["anatomy"] - # Find last workfile - file_template = anatomy.templates["work"]["file"] - workdir_data.update({ - "version": 1, - "user": os.environ.get("PYPE_USERNAME") or getpass.getuser(), - "ext": extensions[0] - }) - - last_workfile_path = avalon.api.last_workfile( - workdir, file_template, workdir_data, extensions, True - ) - - if os.path.exists(last_workfile_path): - self.log.debug(( - "Workfiles for launch context does not exists" - " yet but path will be set." - )) - self.log.debug( - "Setting last workfile path: {}".format(last_workfile_path) - ) - - self.env["AVALON_LAST_WORKFILE"] = last_workfile_path - self.data["last_workfile_path"] = last_workfile_path - - def should_start_last_workfile(self, project_name, host_name, task_name): - """Define if host should start last version workfile if possible. - - Default output is `False`. Can be overriden with environment variable - `AVALON_OPEN_LAST_WORKFILE`, valid values without case sensitivity are - `"0", "1", "true", "false", "yes", "no"`. - - Args: - project_name (str): Name of project. - host_name (str): Name of host which is launched. In avalon's - application context it's value stored in app definition under - key `"application_dir"`. Is not case sensitive. - task_name (str): Name of task which is used for launching the host. - Task name is not case sensitive. - - Returns: - bool: True if host should start workfile. - - """ - default_output = env_value_to_bool( - "AVALON_OPEN_LAST_WORKFILE", default=False - ) - # TODO convert to settings - try: - startup_presets = ( - config.get_presets(project_name) - .get("tools", {}) - .get("workfiles", {}) - .get("last_workfile_on_startup") - ) - except Exception: - startup_presets = None - self.log.warning("Couldn't load pype's presets", exc_info=True) - - if not startup_presets: - return default_output - - host_name_lowered = host_name.lower() - task_name_lowered = task_name.lower() - - max_points = 2 - matching_points = -1 - matching_item = None - for item in startup_presets: - hosts = item.get("hosts") or tuple() - tasks = item.get("tasks") or tuple() - - hosts_lowered = tuple(_host_name.lower() for _host_name in hosts) - # Skip item if has set hosts and current host is not in - if hosts_lowered and host_name_lowered not in hosts_lowered: - continue - - tasks_lowered = tuple(_task_name.lower() for _task_name in tasks) - # Skip item if has set tasks and current task is not in - if tasks_lowered: - task_match = False - for task_regex in compile_list_of_regexes(tasks_lowered): - if re.match(task_regex, task_name_lowered): - task_match = True - break - - if not task_match: - continue - - points = int(bool(hosts_lowered)) + int(bool(tasks_lowered)) - if points > matching_points: - matching_item = item - matching_points = points - - if matching_points == max_points: - break - - if matching_item is not None: - output = matching_item.get("enabled") - if output is None: - output = default_output - return output - return default_output - def after_launch_procedures(self): self._ftrack_after_launch_procedure() From a1a48fbb7ae1ad04582519bb899200e99d44d480 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 17:30:30 +0100 Subject: [PATCH 019/279] moved ftrack logic from application context to post launch hook --- pype/hooks/global/post_ftrack_changes.py | 184 +++++++++++++++++++++++ pype/lib/applications.py | 167 -------------------- 2 files changed, 184 insertions(+), 167 deletions(-) create mode 100644 pype/hooks/global/post_ftrack_changes.py diff --git a/pype/hooks/global/post_ftrack_changes.py b/pype/hooks/global/post_ftrack_changes.py new file mode 100644 index 0000000000..6dfde5409a --- /dev/null +++ b/pype/hooks/global/post_ftrack_changes.py @@ -0,0 +1,184 @@ +import os + +import ftrack_api +from pype.api import config +from pype.lib import LaunchHook + + +class PostFtrackHook(LaunchHook): + order = None + + def execute(self): + project_name = self.data.get("project_name") + asset_name = self.data.get("asset_name") + task_name = self.data.get("task_name") + + missing_context_keys = set() + if not project_name: + missing_context_keys.add("project_name") + if not asset_name: + missing_context_keys.add("asset_name") + if not task_name: + missing_context_keys.add("task_name") + + if missing_context_keys: + missing_keys_str = ", ".join([ + "\"{}\"".format(key) for key in missing_context_keys + ]) + self.log.debug("Hook {} skipped. Missing data keys: {}".format( + self.__class__.__name__, missing_keys_str + )) + return + + required_keys = ("FTRACK_SERVER", "FTRACK_API_USER", "FTRACK_API_KEY") + for key in required_keys: + if not os.environ.get(key): + self.log.debug(( + "Missing required environment \"{}\"" + " for Ftrack after launch procedure." + ).format(key)) + return + + try: + session = ftrack_api.Session(auto_connect_event_hub=True) + self.log.debug("Ftrack session created") + except Exception: + self.log.warning("Couldn't create Ftrack session") + return + + try: + entity = self.find_ftrack_task_entity( + session, project_name, asset_name, task_name + ) + if entity: + self.ftrack_status_change(session, entity, project_name) + self.start_timer(session, entity, ftrack_api) + except Exception: + self.log.warning( + "Couldn't finish Ftrack procedure.", exc_info=True + ) + return + + finally: + session.close() + + def find_ftrack_task_entity( + self, session, project_name, asset_name, task_name + ): + project_entity = session.query( + "Project where full_name is \"{}\"".format(project_name) + ).first() + if not project_entity: + self.log.warning( + "Couldn't find project \"{}\" in Ftrack.".format(project_name) + ) + return + + potential_task_entities = session.query(( + "TypedContext where parent.name is \"{}\" and project_id is \"{}\"" + ).format(asset_name, project_entity["id"])).all() + filtered_entities = [] + for _entity in potential_task_entities: + if ( + _entity.entity_type.lower() == "task" + and _entity["name"] == task_name + ): + filtered_entities.append(_entity) + + if not filtered_entities: + self.log.warning(( + "Couldn't find task \"{}\" under parent \"{}\" in Ftrack." + ).format(task_name, asset_name)) + return + + if len(filtered_entities) > 1: + self.log.warning(( + "Found more than one task \"{}\"" + " under parent \"{}\" in Ftrack." + ).format(task_name, asset_name)) + return + + return filtered_entities[0] + + def ftrack_status_change(self, session, entity, project_name): + # TODO use settings + presets = config.get_presets(project_name)["ftrack"]["ftrack_config"] + statuses = presets.get("status_update") + if not statuses: + return + + actual_status = entity["status"]["name"].lower() + already_tested = set() + ent_path = "/".join( + [ent["name"] for ent in entity["link"]] + ) + while True: + next_status_name = None + for key, value in statuses.items(): + if key in already_tested: + continue + if actual_status in value or "_any_" in value: + if key != "_ignore_": + next_status_name = key + already_tested.add(key) + break + already_tested.add(key) + + if next_status_name is None: + break + + try: + query = "Status where name is \"{}\"".format( + next_status_name + ) + status = session.query(query).one() + + entity["status"] = status + session.commit() + self.log.debug("Changing status to \"{}\" <{}>".format( + next_status_name, ent_path + )) + break + + except Exception: + session.rollback() + msg = ( + "Status \"{}\" in presets wasn't found" + " on Ftrack entity type \"{}\"" + ).format(next_status_name, entity.entity_type) + self.log.warning(msg) + + def start_timer(self, session, entity, _ftrack_api): + """Start Ftrack timer on task from context.""" + self.log.debug("Triggering timer start.") + + user_entity = session.query("User where username is \"{}\"".format( + os.environ["FTRACK_API_USER"] + )).first() + if not user_entity: + self.log.warning( + "Couldn't find user with username \"{}\" in Ftrack".format( + os.environ["FTRACK_API_USER"] + ) + ) + return + + source = { + "user": { + "id": user_entity["id"], + "username": user_entity["username"] + } + } + event_data = { + "actionIdentifier": "start.timer", + "selection": [{"entityId": entity["id"], "entityType": "task"}] + } + session.event_hub.publish( + _ftrack_api.event.base.Event( + topic="ftrack.action.launch", + data=event_data, + source=source + ), + on_error="ignore" + ) + self.log.debug("Timer start triggered successfully.") diff --git a/pype/lib/applications.py b/pype/lib/applications.py index 3804db1ed1..47cb1c7176 100644 --- a/pype/lib/applications.py +++ b/pype/lib/applications.py @@ -1080,170 +1080,3 @@ class ApplicationLaunchContext: if all_cleared: break return args - - def after_launch_procedures(self): - self._ftrack_after_launch_procedure() - - def _ftrack_after_launch_procedure(self): - # TODO move to launch hook - project_name = self.data.get("project_name") - asset_name = self.data.get("asset_name") - task_name = self.data.get("task_name") - if ( - not project_name - or not asset_name - or not task_name - ): - return - - required_keys = ("FTRACK_SERVER", "FTRACK_API_USER", "FTRACK_API_KEY") - for key in required_keys: - if not os.environ.get(key): - self.log.debug(( - "Missing required environment \"{}\"" - " for Ftrack after launch procedure." - ).format(key)) - return - - try: - import ftrack_api - session = ftrack_api.Session(auto_connect_event_hub=True) - self.log.debug("Ftrack session created") - except Exception: - self.log.warning("Couldn't create Ftrack session") - return - - try: - entity = self._find_ftrack_task_entity( - session, project_name, asset_name, task_name - ) - self._ftrack_status_change(session, entity, project_name) - self._start_timer(session, entity, ftrack_api) - except Exception: - self.log.warning( - "Couldn't finish Ftrack procedure.", exc_info=True - ) - return - - finally: - session.close() - - def _find_ftrack_task_entity( - self, session, project_name, asset_name, task_name - ): - project_entity = session.query( - "Project where full_name is \"{}\"".format(project_name) - ).first() - if not project_entity: - self.log.warning( - "Couldn't find project \"{}\" in Ftrack.".format(project_name) - ) - return - - potential_task_entities = session.query(( - "TypedContext where parent.name is \"{}\" and project_id is \"{}\"" - ).format(asset_name, project_entity["id"])).all() - filtered_entities = [] - for _entity in potential_task_entities: - if ( - _entity.entity_type.lower() == "task" - and _entity["name"] == task_name - ): - filtered_entities.append(_entity) - - if not filtered_entities: - self.log.warning(( - "Couldn't find task \"{}\" under parent \"{}\" in Ftrack." - ).format(task_name, asset_name)) - return - - if len(filtered_entities) > 1: - self.log.warning(( - "Found more than one task \"{}\"" - " under parent \"{}\" in Ftrack." - ).format(task_name, asset_name)) - return - - return filtered_entities[0] - - def _ftrack_status_change(self, session, entity, project_name): - from pype.api import config - presets = config.get_presets(project_name)["ftrack"]["ftrack_config"] - statuses = presets.get("status_update") - if not statuses: - return - - actual_status = entity["status"]["name"].lower() - already_tested = set() - ent_path = "/".join( - [ent["name"] for ent in entity["link"]] - ) - while True: - next_status_name = None - for key, value in statuses.items(): - if key in already_tested: - continue - if actual_status in value or "_any_" in value: - if key != "_ignore_": - next_status_name = key - already_tested.add(key) - break - already_tested.add(key) - - if next_status_name is None: - break - - try: - query = "Status where name is \"{}\"".format( - next_status_name - ) - status = session.query(query).one() - - entity["status"] = status - session.commit() - self.log.debug("Changing status to \"{}\" <{}>".format( - next_status_name, ent_path - )) - break - - except Exception: - session.rollback() - msg = ( - "Status \"{}\" in presets wasn't found" - " on Ftrack entity type \"{}\"" - ).format(next_status_name, entity.entity_type) - self.log.warning(msg) - - def _start_timer(self, session, entity, _ftrack_api): - self.log.debug("Triggering timer start.") - - user_entity = session.query("User where username is \"{}\"".format( - os.environ["FTRACK_API_USER"] - )).first() - if not user_entity: - self.log.warning( - "Couldn't find user with username \"{}\" in Ftrack".format( - os.environ["FTRACK_API_USER"] - ) - ) - return - - source = { - "user": { - "id": user_entity["id"], - "username": user_entity["username"] - } - } - event_data = { - "actionIdentifier": "start.timer", - "selection": [{"entityId": entity["id"], "entityType": "task"}] - } - session.event_hub.publish( - _ftrack_api.event.base.Event( - topic="ftrack.action.launch", - data=event_data, - source=source - ), - on_error="ignore" - ) - self.log.debug("Timer start triggered successfully.") From f97ae3f2690845426cb1856d248fb82e55084a5c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 17:30:48 +0100 Subject: [PATCH 020/279] renamed file to start with pre_* --- ...l_host_data.py => pre_global_host_data.py} | 53 +++++++++---------- 1 file changed, 25 insertions(+), 28 deletions(-) rename pype/hooks/global/{global_host_data.py => pre_global_host_data.py} (87%) diff --git a/pype/hooks/global/global_host_data.py b/pype/hooks/global/pre_global_host_data.py similarity index 87% rename from pype/hooks/global/global_host_data.py rename to pype/hooks/global/pre_global_host_data.py index 3f82f3b099..0b501212a0 100644 --- a/pype/hooks/global/global_host_data.py +++ b/pype/hooks/global/pre_global_host_data.py @@ -38,7 +38,7 @@ class GlobalHostDataHook(LaunchHook): def prepare_global_data(self): """Prepare global objects to `data` that will be used for sure.""" # Mongo documents - project_name = self.launch_context.data.get("project_name") + project_name = self.data.get("project_name") if not project_name: self.log.info( "Skipping global data preparation." @@ -48,20 +48,20 @@ class GlobalHostDataHook(LaunchHook): self.log.debug("Project name is set to \"{}\"".format(project_name)) # Anatomy - self.launch_context.data["anatomy"] = Anatomy(project_name) + self.data["anatomy"] = Anatomy(project_name) # Mongo connection dbcon = avalon.api.AvalonMongoDB() dbcon.Session["AVALON_PROJECT"] = project_name dbcon.install() - self.launch_context.data["dbcon"] = dbcon + self.data["dbcon"] = dbcon # Project document project_doc = dbcon.find_one({"type": "project"}) - self.launch_context.data["project_doc"] = project_doc + self.data["project_doc"] = project_doc - asset_name = self.launch_context.data.get("asset_name") + asset_name = self.data.get("asset_name") if not asset_name: self.log.warning( "Asset name was not set. Skipping asset document query." @@ -72,7 +72,7 @@ class GlobalHostDataHook(LaunchHook): "type": "asset", "name": asset_name }) - self.launch_context.data["asset_doc"] = asset_doc + self.data["asset_doc"] = asset_doc def _merge_env(self, env, current_env): """Modified function(merge) from acre module.""" @@ -86,12 +86,9 @@ class GlobalHostDataHook(LaunchHook): def prepare_host_environments(self): """Modify launch environments based on launched app and context.""" # Keys for getting environments - env_keys = [ - self.launch_context.host_name, - self.launch_context.app_name - ] + env_keys = [self.host_name, self.app_name] - asset_doc = self.launch_context.data.get("asset_doc") + asset_doc = self.data.get("asset_doc") if asset_doc: # Add tools environments for key in asset_doc["data"].get("tools_env") or []: @@ -107,7 +104,7 @@ class GlobalHostDataHook(LaunchHook): "Finding environment groups for keys: {}".format(env_keys) ) - settings_env = self.launch_context.data["settings_env"] + settings_env = self.data["settings_env"] env_values = {} for env_key in env_keys: _env_values = settings_env.get(env_key) @@ -129,9 +126,9 @@ class GlobalHostDataHook(LaunchHook): def prepare_context_environments(self): """Modify launch environemnts with context data for launched host.""" # Context environments - project_doc = self.launch_context.data.get("project_doc") - asset_doc = self.launch_context.data.get("asset_doc") - task_name = self.launch_context.data.get("task_name") + project_doc = self.data.get("project_doc") + asset_doc = self.data.get("asset_doc") + task_name = self.data.get("task_name") if ( not project_doc or not asset_doc @@ -146,10 +143,10 @@ class GlobalHostDataHook(LaunchHook): workdir_data = self._prepare_workdir_data( project_doc, asset_doc, task_name ) - self.launch_context.data["workdir_data"] = workdir_data + self.data["workdir_data"] = workdir_data hierarchy = workdir_data["hierarchy"] - anatomy = self.launch_context.data["anatomy"] + anatomy = self.data["anatomy"] try: anatomy_filled = anatomy.format(workdir_data) @@ -169,8 +166,8 @@ class GlobalHostDataHook(LaunchHook): "AVALON_PROJECT": project_doc["name"], "AVALON_ASSET": asset_doc["name"], "AVALON_TASK": task_name, - "AVALON_APP": self.launch_context.host_name, - "AVALON_APP_NAME": self.launch_context.app_name, + "AVALON_APP": self.host_name, + "AVALON_APP_NAME": self.app_name, "AVALON_HIERARCHY": hierarchy, "AVALON_WORKDIR": workdir } @@ -193,7 +190,7 @@ class GlobalHostDataHook(LaunchHook): }, "task": task_name, "asset": asset_doc["name"], - "app": self.launch_context.host_name, + "app": self.host_name, "hierarchy": hierarchy } return data @@ -211,7 +208,7 @@ class GlobalHostDataHook(LaunchHook): Args: workdir (str): Path to folder where workfiles should be stored. """ - _workdir_data = self.launch_context.data.get("workdir_data") + _workdir_data = self.data.get("workdir_data") if not _workdir_data: self.log.info( "Skipping last workfile preparation." @@ -220,12 +217,12 @@ class GlobalHostDataHook(LaunchHook): return workdir_data = copy.deepcopy(_workdir_data) - project_name = self.launch_context.data["project_name"] - task_name = self.launch_context.data["task_name"] + project_name = self.data["project_name"] + task_name = self.data["task_name"] start_last_workfile = self.should_start_last_workfile( - project_name, self.launch_context.host_name, task_name + project_name, self.host_name, task_name ) - self.launch_context.data["start_last_workfile"] = start_last_workfile + self.data["start_last_workfile"] = start_last_workfile # Store boolean as "0"(False) or "1"(True) self.launch_context.env["AVALON_OPEN_LAST_WORKFILE"] = ( @@ -240,10 +237,10 @@ class GlobalHostDataHook(LaunchHook): # Last workfile path last_workfile_path = "" extensions = avalon.api.HOST_WORKFILE_EXTENSIONS.get( - self.launch_context.host_name + self.host_name ) if extensions: - anatomy = self.launch_context.data["anatomy"] + anatomy = self.data["anatomy"] # Find last workfile file_template = anatomy.templates["work"]["file"] workdir_data.update({ @@ -266,7 +263,7 @@ class GlobalHostDataHook(LaunchHook): ) self.launch_context.env["AVALON_LAST_WORKFILE"] = last_workfile_path - self.launch_context.data["last_workfile_path"] = last_workfile_path + self.data["last_workfile_path"] = last_workfile_path def should_start_last_workfile(self, project_name, host_name, task_name): """Define if host should start last version workfile if possible. From 88316fe4211546d5290faf7204f58506e1ff4264 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 17:56:58 +0100 Subject: [PATCH 021/279] prelaunch and postlaunch hooks are diferentiated by inherit class --- pype/hooks/global/post_ftrack_changes.py | 4 +- pype/hooks/global/pre_global_host_data.py | 4 +- pype/lib/__init__.py | 6 +- pype/lib/applications.py | 127 +++++++++++++--------- 4 files changed, 82 insertions(+), 59 deletions(-) diff --git a/pype/hooks/global/post_ftrack_changes.py b/pype/hooks/global/post_ftrack_changes.py index 6dfde5409a..144f618620 100644 --- a/pype/hooks/global/post_ftrack_changes.py +++ b/pype/hooks/global/post_ftrack_changes.py @@ -2,10 +2,10 @@ import os import ftrack_api from pype.api import config -from pype.lib import LaunchHook +from pype.lib import PostLaunchHook -class PostFtrackHook(LaunchHook): +class PostFtrackHook(PostLaunchHook): order = None def execute(self): diff --git a/pype/hooks/global/pre_global_host_data.py b/pype/hooks/global/pre_global_host_data.py index 0b501212a0..787460019d 100644 --- a/pype/hooks/global/pre_global_host_data.py +++ b/pype/hooks/global/pre_global_host_data.py @@ -10,7 +10,7 @@ from pype.api import ( ) from pype.lib import ( env_value_to_bool, - LaunchHook, + PreLaunchHook, ApplicationLaunchFailed ) @@ -18,7 +18,7 @@ import acre import avalon.api -class GlobalHostDataHook(LaunchHook): +class GlobalHostDataHook(PreLaunchHook): order = -100 def execute(self): diff --git a/pype/lib/__init__.py b/pype/lib/__init__.py index 512cb12e37..ecdd155c99 100644 --- a/pype/lib/__init__.py +++ b/pype/lib/__init__.py @@ -34,7 +34,8 @@ from .applications import ( ApplictionExecutableNotFound, ApplicationNotFound, ApplicationManager, - LaunchHook, + PreLaunchHook, + PostLaunchHook, launch_application, ApplicationAction, _subprocess @@ -79,7 +80,8 @@ __all__ = [ "ApplictionExecutableNotFound", "ApplicationNotFound", "ApplicationManager", - "LaunchHook", + "PreLaunchHook", + "PostLaunchHook", "launch_application", "ApplicationAction", diff --git a/pype/lib/applications.py b/pype/lib/applications.py index 47cb1c7176..9d34a8b22c 100644 --- a/pype/lib/applications.py +++ b/pype/lib/applications.py @@ -704,11 +704,9 @@ class Application: @six.add_metaclass(ABCMeta) class LaunchHook: - """Abstract class from all hooks should inherit.""" + """Abstract base class of launch hook.""" # Order of prelaunch hook, will be executed as last if set to None. order = None - # If hook should be executed befor or after application launch - prelaunch = True # List of host implementations, skipped if empty. hosts = [] # List of platform availability, skipped if empty. @@ -790,6 +788,26 @@ class LaunchHook: pass +class PreLaunchHook(LaunchHook): + """Abstract class of prelaunch hook. + + This launch hook will be processed before application is launched. + + If any exception will happen during processing the application won't be + launched. + """ + + +class PostLaunchHook(LaunchHook): + """Abstract class of postlaunch hook. + + This launch hook will be processed after application is launched. + + Nothing will happen if any exception will happen during processing. And + processing of other postlaunch hooks won't stop either. + """ + + class ApplicationLaunchContext: """Context of launching application. @@ -918,7 +936,10 @@ class ApplicationLaunchContext: "\n- ".join(paths) )) - classes = [] + all_classes = { + "pre": [], + "post": [] + } for path in paths: if not os.path.exists(path): self.log.info( @@ -928,59 +949,55 @@ class ApplicationLaunchContext: modules = modules_from_path(path) for _module in modules: - classes.extend(classes_from_module(LaunchHook, _module)) - - pre_hooks_with_order = [] - pre_hooks_without_order = [] - post_hooks_with_order = [] - post_hooks_without_order = [] - for klass in classes: - try: - hook = klass(self) - if not hook.is_valid: - self.log.debug( - "Hook is not valid for curent launch context." - ) - continue - - if inspect.isabstract(hook): - self.log.debug("Skipped abstract hook: {}".format( - str(hook) - )) - continue - - # Separate hooks if should be executed before or after launch - if hook.prelaunch: - if hook.order is None: - pre_hooks_without_order.append(hook) - else: - pre_hooks_with_order.append(hook) - else: - if hook.order is None: - post_hooks_with_order.append(hook) - else: - post_hooks_without_order.append(hook) - - except Exception: - self.log.warning( - "Initialization of hook failed. {}".format(str(klass)), - exc_info=True + all_classes["pre"].extend( + classes_from_module(PreLaunchHook, _module) + ) + all_classes["post"].extend( + classes_from_module(PostLaunchHook, _module) ) - # Sort hooks with order by order - pre_hooks_ordered = list(sorted( - pre_hooks_with_order, key=lambda obj: obj.order - )) - post_hooks_ordered = list(sorted( - post_hooks_with_order, key=lambda obj: obj.order - )) + for launch_type, classes in all_classes.items(): + hooks_with_order = [] + hooks_without_order = [] + for klass in classes: + try: + hook = klass(self) + if not hook.is_valid: + self.log.debug( + "Hook is not valid for curent launch context." + ) + continue - # Extend ordered hooks with hooks without defined order - pre_hooks_ordered.extend(pre_hooks_without_order) - post_hooks_ordered.extend(post_hooks_without_order) + if inspect.isabstract(hook): + self.log.debug("Skipped abstract hook: {}".format( + str(hook) + )) + continue + + # Separate hooks by pre/post class + if hook.order is None: + hooks_without_order.append(hook) + else: + hooks_with_order.append(hook) + + except Exception: + self.log.warning( + "Initialization of hook failed. {}".format(str(klass)), + exc_info=True + ) + + # Sort hooks with order by order + ordered_hooks = list(sorted( + hooks_with_order, key=lambda obj: obj.order + )) + # Extend ordered hooks with hooks without defined order + ordered_hooks.extend(hooks_without_order) + + if launch_type == "pre": + self.prelaunch_hooks = ordered_hooks + else: + self.postlaunch_hooks = ordered_hooks - self.prelaunch_hooks = pre_hooks_ordered - self.postlaunch_hooks = post_hooks_ordered self.log.debug("Found {} prelaunch and {} postlaunch hooks.".format( len(self.prelaunch_hooks), len(self.postlaunch_hooks) )) @@ -1019,6 +1036,8 @@ class ApplicationLaunchContext: )) prelaunch_hook.execute() + self.log.debug("All prelaunch hook executed. Starting new process.") + # Prepare subprocess args args = self.clear_launch_args(self.launch_args) self.log.debug( @@ -1044,6 +1063,8 @@ class ApplicationLaunchContext: exc_info=True ) + self.log.debug("Launch of {} finished.".format(self.app_name)) + return self.process @staticmethod From 8204382719d3e2d5479dfcdd5718a78ab7d6f9f8 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Tue, 24 Nov 2020 18:13:09 +0100 Subject: [PATCH 022/279] fix multiple camera prefix --- pype/hosts/maya/expected_files.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/hosts/maya/expected_files.py b/pype/hosts/maya/expected_files.py index 8d225bc13d..7324f1cfd0 100644 --- a/pype/hosts/maya/expected_files.py +++ b/pype/hosts/maya/expected_files.py @@ -266,8 +266,8 @@ class AExpectedFiles: def _generate_single_file_sequence(self, layer_data): expected_files = [] - file_prefix = layer_data["filePrefix"] for cam in layer_data["cameras"]: + file_prefix = layer_data["filePrefix"] mappings = ( (R_SUBSTITUTE_SCENE_TOKEN, layer_data["sceneName"]), (R_SUBSTITUTE_LAYER_TOKEN, layer_data["layerName"]), @@ -299,9 +299,9 @@ class AExpectedFiles: def _generate_aov_file_sequences(self, layer_data): expected_files = [] aov_file_list = {} - file_prefix = layer_data["filePrefix"] for aov in layer_data["enabledAOVs"]: for cam in layer_data["cameras"]: + file_prefix = layer_data["filePrefix"] mappings = ( (R_SUBSTITUTE_SCENE_TOKEN, layer_data["sceneName"]), From b1c587ae8347d97ba96e202dad219edc1cacc388 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 18:18:39 +0100 Subject: [PATCH 023/279] added few basic prelaunch hooks for nuke --- pype/hooks/hiero/pre_launch_args.py | 18 ++++++++++++++++++ pype/hooks/nukestudio/pre_launch_args.py | 18 ++++++++++++++++++ pype/hooks/nukex/pre_launch_args.py | 18 ++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 pype/hooks/hiero/pre_launch_args.py create mode 100644 pype/hooks/nukestudio/pre_launch_args.py create mode 100644 pype/hooks/nukex/pre_launch_args.py diff --git a/pype/hooks/hiero/pre_launch_args.py b/pype/hooks/hiero/pre_launch_args.py new file mode 100644 index 0000000000..20bac0ca8e --- /dev/null +++ b/pype/hooks/hiero/pre_launch_args.py @@ -0,0 +1,18 @@ +from pype.lib import PreLaunchHook + + +class HieroLaunchArguments(PreLaunchHook): + order = 0 + + def execute(self): + """Prepare suprocess launch arguments for NukeX.""" + # Get executable + executable = self.launch_context.launch_args[0] + + if isinstance(executable, str): + executable = [executable] + + # Add `nukex` argument and make sure it's bind to execuable + executable.append("--hiero") + + self.launch_context.launch_args[0] = executable diff --git a/pype/hooks/nukestudio/pre_launch_args.py b/pype/hooks/nukestudio/pre_launch_args.py new file mode 100644 index 0000000000..a1c8dda314 --- /dev/null +++ b/pype/hooks/nukestudio/pre_launch_args.py @@ -0,0 +1,18 @@ +from pype.lib import PreLaunchHook + + +class NukeStudioLaunchArguments(PreLaunchHook): + order = 0 + + def execute(self): + """Prepare suprocess launch arguments for NukeX.""" + # Get executable + executable = self.launch_context.launch_args[0] + + if isinstance(executable, str): + executable = [executable] + + # Add `nukex` argument and make sure it's bind to execuable + executable.append("--studio") + + self.launch_context.launch_args[0] = executable diff --git a/pype/hooks/nukex/pre_launch_args.py b/pype/hooks/nukex/pre_launch_args.py new file mode 100644 index 0000000000..b204cf0cbb --- /dev/null +++ b/pype/hooks/nukex/pre_launch_args.py @@ -0,0 +1,18 @@ +from pype.lib import PreLaunchHook + + +class NukeXLaunchArguments(PreLaunchHook): + order = 0 + + def execute(self): + """Prepare suprocess launch arguments for NukeX.""" + # Get executable + executable = self.launch_context.launch_args[0] + + if isinstance(executable, str): + executable = [executable] + + # Add `nukex` argument and make sure it's bind to execuable + executable.append("--nukex") + + self.launch_context.launch_args[0] = executable From 8abd04959ad7b7e3bc9f8140c2073ae84c9c6f61 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 18:25:26 +0100 Subject: [PATCH 024/279] added prelaunch hook for tvpaint for installation of pywin32 --- pype/hooks/tvpaint/pre_install_pywin.py | 34 +++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 pype/hooks/tvpaint/pre_install_pywin.py diff --git a/pype/hooks/tvpaint/pre_install_pywin.py b/pype/hooks/tvpaint/pre_install_pywin.py new file mode 100644 index 0000000000..20d4b2aae7 --- /dev/null +++ b/pype/hooks/tvpaint/pre_install_pywin.py @@ -0,0 +1,34 @@ +from pype.lib import ( + PreLaunchHook, + ApplicationLaunchFailed, + _subprocess +) + + +class PreInstallPyWin(PreLaunchHook): + """Hook makes sure there is installed python module pywin32 on windows.""" + # WARNING This hook will probably be deprecated in Pype 3 - kept for test + order = 10 + hosts = ["tvpaint"] + platforms = ["windows"] + + def execute(self): + installed = False + try: + from win32com.shell import shell + self.log.debug("Python module `pywin32` already installed.") + installed = True + except Exception: + pass + + if installed: + return + + try: + output = _subprocess( + ["pip", "install", "pywin32==227"], logger=self.log + ) + except RuntimeError: + msg = "Installation of python module `pywin32` crashed." + self.log.warning(msg, exc_info=True) + raise ApplicationLaunchFailed(msg) From b9c569c159a824489832dfea5fff5b5fca8dac6a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 18:59:33 +0100 Subject: [PATCH 025/279] added hosts filtering --- pype/hooks/hiero/pre_launch_args.py | 3 ++- pype/hooks/nukestudio/pre_launch_args.py | 1 + pype/hooks/nukex/pre_launch_args.py | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/pype/hooks/hiero/pre_launch_args.py b/pype/hooks/hiero/pre_launch_args.py index 20bac0ca8e..ff5e3d79e5 100644 --- a/pype/hooks/hiero/pre_launch_args.py +++ b/pype/hooks/hiero/pre_launch_args.py @@ -3,7 +3,8 @@ from pype.lib import PreLaunchHook class HieroLaunchArguments(PreLaunchHook): order = 0 - + hosts = ["hiero"] + def execute(self): """Prepare suprocess launch arguments for NukeX.""" # Get executable diff --git a/pype/hooks/nukestudio/pre_launch_args.py b/pype/hooks/nukestudio/pre_launch_args.py index a1c8dda314..b0ca41a614 100644 --- a/pype/hooks/nukestudio/pre_launch_args.py +++ b/pype/hooks/nukestudio/pre_launch_args.py @@ -3,6 +3,7 @@ from pype.lib import PreLaunchHook class NukeStudioLaunchArguments(PreLaunchHook): order = 0 + hosts = ["nukestudio"] def execute(self): """Prepare suprocess launch arguments for NukeX.""" diff --git a/pype/hooks/nukex/pre_launch_args.py b/pype/hooks/nukex/pre_launch_args.py index b204cf0cbb..16a83cfd63 100644 --- a/pype/hooks/nukex/pre_launch_args.py +++ b/pype/hooks/nukex/pre_launch_args.py @@ -3,6 +3,7 @@ from pype.lib import PreLaunchHook class NukeXLaunchArguments(PreLaunchHook): order = 0 + hosts = ["nukex"] def execute(self): """Prepare suprocess launch arguments for NukeX.""" From 163c2d7e7dc0e01cb8fb4347366fd7456936da09 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 19:00:01 +0100 Subject: [PATCH 026/279] implemented tvpaint prelaunch hook which modify launch arguments --- pype/hooks/tvpaint/pre_launch_args.py | 99 +++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 pype/hooks/tvpaint/pre_launch_args.py diff --git a/pype/hooks/tvpaint/pre_launch_args.py b/pype/hooks/tvpaint/pre_launch_args.py new file mode 100644 index 0000000000..9f90398433 --- /dev/null +++ b/pype/hooks/tvpaint/pre_launch_args.py @@ -0,0 +1,99 @@ +import os +import shutil + +from pype.hosts import tvpaint +from pype.lib import ( + PreLaunchHook, + ApplicationLaunchFailed, + _subprocess +) +import avalon + + +class TvpaintPrelaunchHook(PreLaunchHook): + """Launch arguments preparation. + + Hook add python executable and script path to tvpaint implementation before + tvpaint executable and add last workfile path to launch arguments. + + Existence of last workfile is checked. If workfile does not exists tries + to copy templated workfile from predefined path. + """ + hosts = ["tvpaint"] + + def execute(self): + tvpaint_executable = self.launch_context.launch_args.pop(0) + + # This should never be used! + remainders = [] + while self.launch_context.launch_args: + remainders.append(self.launch_context.launch_args.pop(0)) + + self.launch_context.launch_args.append( + self.main_executable() + ) + self.launch_context.launch_args.append( + "\"{}\"".format(self.launch_script_path()) + ) + self.launch_context.launch_args.append( + "\"{}\"".format(tvpaint_executable) + ) + + # Add workfile to launch arguments + workfile_path = self.workfile_path() + if workfile_path: + self.launch_context.launch_args.append( + "\"{}\"".format(workfile_path) + ) + + if remainders: + self.log.warning(( + "There are unexpected launch arguments in TVPaint launch. {}" + ).format(str(remainders))) + self.launch_context.launch_args.extend(remainders) + + def main_executable(self): + """Should lead to python executable.""" + # TODO change in Pype 3 + return os.environ["PYPE_PYTHON_EXE"] + + def launch_script_path(self): + avalon_dir = os.path.dirname(os.path.abspath(avalon.__file__)) + script_path = os.path.join( + avalon_dir, + "tvpaint", + "launch_script.py" + ) + return script_path + + def workfile_path(self): + workfile_path = self.data["last_workfile"] + + # copy workfile from template if doesnt exist any on path + if not os.path.exists(workfile_path): + # TODO add ability to set different template workfile path via + # settings + pype_dir = os.path.dirname(os.path.abspath(tvpaint.__file__)) + template_path = os.path.join(pype_dir, "template.tvpp") + + if not os.path.exists(template_path): + self.log.warning( + "Couldn't find workfile template file in {}".format( + template_path + ) + ) + return + + self.log.info( + f"Creating workfile from template: \"{template_path}\"" + ) + + # Copy template workfile to new destinantion + shutil.copy2( + os.path.normpath(template_path), + os.path.normpath(workfile_path) + ) + + self.log.info(f"Workfile to open: \"{workfile_path}\"") + + return workfile_path From 1e91b84017783ebe5304880037945070b15dd444 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 19:25:44 +0100 Subject: [PATCH 027/279] add last workfile if should start last workfile --- pype/hooks/hiero/pre_launch_args.py | 10 +++++++++- pype/hooks/nukestudio/pre_launch_args.py | 8 ++++++++ pype/hooks/nukex/pre_launch_args.py | 8 ++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/pype/hooks/hiero/pre_launch_args.py b/pype/hooks/hiero/pre_launch_args.py index ff5e3d79e5..cb03f03b88 100644 --- a/pype/hooks/hiero/pre_launch_args.py +++ b/pype/hooks/hiero/pre_launch_args.py @@ -1,10 +1,11 @@ +import os from pype.lib import PreLaunchHook class HieroLaunchArguments(PreLaunchHook): order = 0 hosts = ["hiero"] - + def execute(self): """Prepare suprocess launch arguments for NukeX.""" # Get executable @@ -17,3 +18,10 @@ class HieroLaunchArguments(PreLaunchHook): executable.append("--hiero") self.launch_context.launch_args[0] = executable + + if self.data.get("start_last_workfile"): + last_workfile = self.data.get("last_workfile_path") + if os.path.exists(last_workfile): + self.launch_context.launch_args.append( + "\"{}\"".format(last_workfile) + ) diff --git a/pype/hooks/nukestudio/pre_launch_args.py b/pype/hooks/nukestudio/pre_launch_args.py index b0ca41a614..d567f36ad0 100644 --- a/pype/hooks/nukestudio/pre_launch_args.py +++ b/pype/hooks/nukestudio/pre_launch_args.py @@ -1,3 +1,4 @@ +import os from pype.lib import PreLaunchHook @@ -17,3 +18,10 @@ class NukeStudioLaunchArguments(PreLaunchHook): executable.append("--studio") self.launch_context.launch_args[0] = executable + + if self.data.get("start_last_workfile"): + last_workfile = self.data.get("last_workfile_path") + if os.path.exists(last_workfile): + self.launch_context.launch_args.append( + "\"{}\"".format(last_workfile) + ) diff --git a/pype/hooks/nukex/pre_launch_args.py b/pype/hooks/nukex/pre_launch_args.py index 16a83cfd63..eb0b963926 100644 --- a/pype/hooks/nukex/pre_launch_args.py +++ b/pype/hooks/nukex/pre_launch_args.py @@ -1,3 +1,4 @@ +import os from pype.lib import PreLaunchHook @@ -17,3 +18,10 @@ class NukeXLaunchArguments(PreLaunchHook): executable.append("--nukex") self.launch_context.launch_args[0] = executable + + if self.data.get("start_last_workfile"): + last_workfile = self.data.get("last_workfile_path") + if os.path.exists(last_workfile): + self.launch_context.launch_args.append( + "\"{}\"".format(last_workfile) + ) From cb07c41d92ef3cf68faafa596552ac18223b247c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 20:01:07 +0100 Subject: [PATCH 028/279] added few prelaunch hooks --- .../celaction/pre_celaction_registers.py | 128 ++++++++++++++++++ pype/hooks/fusion/pre_fusion_setup.py | 50 +++++++ pype/hooks/photoshop/pre_launch_args.py | 53 ++++++++ pype/hooks/tvpaint/pre_launch_args.py | 20 +-- 4 files changed, 241 insertions(+), 10 deletions(-) create mode 100644 pype/hooks/celaction/pre_celaction_registers.py create mode 100644 pype/hooks/fusion/pre_fusion_setup.py create mode 100644 pype/hooks/photoshop/pre_launch_args.py diff --git a/pype/hooks/celaction/pre_celaction_registers.py b/pype/hooks/celaction/pre_celaction_registers.py new file mode 100644 index 0000000000..c638ce3c0b --- /dev/null +++ b/pype/hooks/celaction/pre_celaction_registers.py @@ -0,0 +1,128 @@ +import os +import shutil +import winreg +from pype.lib import PreLaunchHook +from pype.hosts import celaction + + +class CelactionPrelaunchHook(PreLaunchHook): + """ + This hook will check if current workfile path has Unreal + project inside. IF not, it initialize it and finally it pass + path to the project by environment variable to Unreal launcher + shell script. + """ + workfile_ext = "scn" + hosts = ["celaction"] + platforms = ["windows"] + + def execute(self): + # Add workfile path to launch arguments + workfile_path = self.workfile_path() + if workfile_path: + self.launch_context.launch_args.append( + "\"{}\"".format(workfile_path) + ) + + project_name = self.data["project_name"] + asset_name = self.data["asset_name"] + task_name = self.data["task_name"] + + # get publish version of celaction + app = "celaction_publish" + + # setting output parameters + path = r"Software\CelAction\CelAction2D\User Settings" + winreg.CreateKey(winreg.HKEY_CURRENT_USER, path) + hKey = winreg.OpenKey( + winreg.HKEY_CURRENT_USER, + "Software\\CelAction\\CelAction2D\\User Settings", 0, + winreg.KEY_ALL_ACCESS) + + # TODO: change to root path and pyblish standalone to premiere way + pype_root_path = os.getenv("PYPE_SETUP_PATH") + path = os.path.join(pype_root_path, + "pype.bat") + + winreg.SetValueEx(hKey, "SubmitAppTitle", 0, winreg.REG_SZ, path) + + parameters = [ + "launch", + f"--app {app}", + f"--project {project_name}", + f"--asset {asset_name}", + f"--task {task_name}", + "--currentFile \\\"\"*SCENE*\"\\\"", + "--chunk 10", + "--frameStart *START*", + "--frameEnd *END*", + "--resolutionWidth *X*", + "--resolutionHeight *Y*", + # "--programDir \"'*PROGPATH*'\"" + ] + winreg.SetValueEx(hKey, "SubmitParametersTitle", 0, winreg.REG_SZ, + " ".join(parameters)) + + # setting resolution parameters + path = r"Software\CelAction\CelAction2D\User Settings\Dialogs" + path += r"\SubmitOutput" + winreg.CreateKey(winreg.HKEY_CURRENT_USER, path) + hKey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, path, 0, + winreg.KEY_ALL_ACCESS) + winreg.SetValueEx(hKey, "SaveScene", 0, winreg.REG_DWORD, 1) + winreg.SetValueEx(hKey, "CustomX", 0, winreg.REG_DWORD, 1920) + winreg.SetValueEx(hKey, "CustomY", 0, winreg.REG_DWORD, 1080) + + # making sure message dialogs don't appear when overwriting + path = r"Software\CelAction\CelAction2D\User Settings\Messages" + path += r"\OverwriteScene" + winreg.CreateKey(winreg.HKEY_CURRENT_USER, path) + hKey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, path, 0, + winreg.KEY_ALL_ACCESS) + winreg.SetValueEx(hKey, "Result", 0, winreg.REG_DWORD, 6) + winreg.SetValueEx(hKey, "Valid", 0, winreg.REG_DWORD, 1) + + path = r"Software\CelAction\CelAction2D\User Settings\Messages" + path += r"\SceneSaved" + winreg.CreateKey(winreg.HKEY_CURRENT_USER, path) + hKey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, path, 0, + winreg.KEY_ALL_ACCESS) + winreg.SetValueEx(hKey, "Result", 0, winreg.REG_DWORD, 1) + winreg.SetValueEx(hKey, "Valid", 0, winreg.REG_DWORD, 1) + + def workfile_path(self): + workfile_path = self.data["last_workfile"] + + # copy workfile from template if doesnt exist any on path + if not os.path.exists(workfile_path): + # TODO add ability to set different template workfile path via + # settings + pype_celaction_dir = os.path.dirname( + os.path.abspath(celaction.__file__) + ) + template_path = os.path.join( + pype_celaction_dir, + "celaction_template_scene.scn" + ) + + if not os.path.exists(template_path): + self.log.warning( + "Couldn't find workfile template file in {}".format( + template_path + ) + ) + return + + self.log.info( + f"Creating workfile from template: \"{template_path}\"" + ) + + # Copy template workfile to new destinantion + shutil.copy2( + os.path.normpath(template_path), + os.path.normpath(workfile_path) + ) + + self.log.info(f"Workfile to open: \"{workfile_path}\"") + + return workfile_path diff --git a/pype/hooks/fusion/pre_fusion_setup.py b/pype/hooks/fusion/pre_fusion_setup.py new file mode 100644 index 0000000000..ac7dda4250 --- /dev/null +++ b/pype/hooks/fusion/pre_fusion_setup.py @@ -0,0 +1,50 @@ +import os +import importlib +from pype.lib import PreLaunchHook +from pype.hosts.fusion import utils + + +class FusionPrelaunch(PreLaunchHook): + """ + This hook will check if current workfile path has Fusion + project inside. + """ + hosts = ["fusion"] + + def execute(self): + # making sure pyton 3.6 is installed at provided path + py36_dir = os.path.normpath(self.env.get("PYTHON36", "")) + assert os.path.isdir(py36_dir), ( + "Python 3.6 is not installed at the provided folder path. Either " + "make sure the `environments\resolve.json` is having correctly " + "set `PYTHON36` or make sure Python 3.6 is installed " + f"in given path. \nPYTHON36E: `{py36_dir}`" + ) + self.log.info(f"Path to Fusion Python folder: `{py36_dir}`...") + self.env["PYTHON36"] = py36_dir + + # setting utility scripts dir for scripts syncing + us_dir = os.path.normpath( + self.env.get("FUSION_UTILITY_SCRIPTS_DIR", "") + ) + assert os.path.isdir(us_dir), ( + "Fusion utility script dir does not exists. Either make sure " + "the `environments\fusion.json` is having correctly set " + "`FUSION_UTILITY_SCRIPTS_DIR` or reinstall DaVinci Resolve. \n" + f"FUSION_UTILITY_SCRIPTS_DIR: `{us_dir}`" + ) + + try: + __import__("avalon.fusion") + __import__("pyblish") + + except ImportError: + self.log.warning( + "pyblish: Could not load Fusion integration.", + exc_info=True + ) + + else: + # Resolve Setup integration + importlib.reload(utils) + utils.setup(self.env) diff --git a/pype/hooks/photoshop/pre_launch_args.py b/pype/hooks/photoshop/pre_launch_args.py new file mode 100644 index 0000000000..bc747dc495 --- /dev/null +++ b/pype/hooks/photoshop/pre_launch_args.py @@ -0,0 +1,53 @@ +import os +import platform + +from pype.lib import PreLaunchHook + + +class PhotoshopPrelaunchHook(PreLaunchHook): + """Launch arguments preparation. + + Hook add python executable and execute python script of photoshop + implementation before photoshop executable. + """ + hosts = ["photoshop"] + + def execute(self): + # Pop tvpaint executable + photoshop_executable = self.launch_context.launch_args.pop(0) + + # Pop rest of launch arguments - There should not be other arguments! + remainders = [] + while self.launch_context.launch_args: + remainders.append(self.launch_context.launch_args.pop(0)) + + python_launch_args = [ + self.python_executable(), + "-c", + ( + "^\"import avalon.photoshop;" + "avalon.photoshop.launch(\"{}\")^\"\"" + ).format(photoshop_executable) + ] + if platform.system().lower() != "windows": + new_launch_args = python_launch_args + else: + new_launch_args = [ + "cmd.exe", + "/k", + "\"{}\"".format(" ".join(python_launch_args)) + ] + + # Append as whole list as these areguments should not be separated + self.launch_context.launch_args.append(new_launch_args) + + if remainders: + self.log.warning(( + "There are unexpected launch arguments in Photoshop launch. {}" + ).format(str(remainders))) + self.launch_context.launch_args.extend(remainders) + + def python_executable(self): + """Should lead to python executable.""" + # TODO change in Pype 3 + return os.environ["PYPE_PYTHON_EXE"] diff --git a/pype/hooks/tvpaint/pre_launch_args.py b/pype/hooks/tvpaint/pre_launch_args.py index 9f90398433..6c59a8ce20 100644 --- a/pype/hooks/tvpaint/pre_launch_args.py +++ b/pype/hooks/tvpaint/pre_launch_args.py @@ -22,30 +22,30 @@ class TvpaintPrelaunchHook(PreLaunchHook): hosts = ["tvpaint"] def execute(self): + # Pop tvpaint executable tvpaint_executable = self.launch_context.launch_args.pop(0) - # This should never be used! + # Pop rest of launch arguments - There should not be other arguments! remainders = [] while self.launch_context.launch_args: remainders.append(self.launch_context.launch_args.pop(0)) - self.launch_context.launch_args.append( - self.main_executable() - ) - self.launch_context.launch_args.append( - "\"{}\"".format(self.launch_script_path()) - ) - self.launch_context.launch_args.append( + new_launch_args = [ + self.main_executable(), + "\"{}\"".format(self.launch_script_path()), "\"{}\"".format(tvpaint_executable) - ) + ] # Add workfile to launch arguments workfile_path = self.workfile_path() if workfile_path: - self.launch_context.launch_args.append( + new_launch_args.append( "\"{}\"".format(workfile_path) ) + # Append as whole list as these areguments should not be separated + self.launch_context.launch_args.append(new_launch_args) + if remainders: self.log.warning(( "There are unexpected launch arguments in TVPaint launch. {}" From 9940ff2fa9ec5dfa2435f364b5543e726999bed7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 24 Nov 2020 20:02:18 +0100 Subject: [PATCH 029/279] added maya --- pype/hooks/maya/pre_launch_args.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 pype/hooks/maya/pre_launch_args.py diff --git a/pype/hooks/maya/pre_launch_args.py b/pype/hooks/maya/pre_launch_args.py new file mode 100644 index 0000000000..6aed54a3c3 --- /dev/null +++ b/pype/hooks/maya/pre_launch_args.py @@ -0,0 +1,17 @@ +import os +from pype.lib import PreLaunchHook + + +class MayaLaunchArguments(PreLaunchHook): + """Add path to last workfile to launch arguments.""" + order = 0 + hosts = ["maya"] + + def execute(self): + """Prepare suprocess launch arguments for NukeX.""" + if self.data.get("start_last_workfile"): + last_workfile = self.data.get("last_workfile_path") + if os.path.exists(last_workfile): + self.launch_context.launch_args.append( + "\"{}\"".format(last_workfile) + ) From 87d30338c4c0ebafd88bc9fd83a6f59b2ff74577 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 09:55:46 +0100 Subject: [PATCH 030/279] added harmony prelaunch --- pype/hooks/harmony/pre_launch_args.py | 53 +++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 pype/hooks/harmony/pre_launch_args.py diff --git a/pype/hooks/harmony/pre_launch_args.py b/pype/hooks/harmony/pre_launch_args.py new file mode 100644 index 0000000000..7047e67616 --- /dev/null +++ b/pype/hooks/harmony/pre_launch_args.py @@ -0,0 +1,53 @@ +import os +import platform + +from pype.lib import PreLaunchHook + + +class HarmonyPrelaunchHook(PreLaunchHook): + """Launch arguments preparation. + + Hook add python executable and execute python script of harmony + implementation before harmony executable. + """ + hosts = ["harmony"] + + def execute(self): + # Pop tvpaint executable + photoshop_executable = self.launch_context.launch_args.pop(0) + + # Pop rest of launch arguments - There should not be other arguments! + remainders = [] + while self.launch_context.launch_args: + remainders.append(self.launch_context.launch_args.pop(0)) + + python_launch_args = [ + self.python_executable(), + "-c", + ( + "^\"import avalon.harmony;" + "avalon.harmony.launch(\"{}\")^\"\"" + ).format(photoshop_executable) + ] + if platform.system().lower() != "windows": + new_launch_args = python_launch_args + else: + new_launch_args = [ + "cmd.exe", + "/k", + "\"{}\"".format(" ".join(python_launch_args)) + ] + + # Append as whole list as these areguments should not be separated + self.launch_context.launch_args.append(new_launch_args) + + if remainders: + self.log.warning(( + "There are unexpected launch arguments in Harmony launch. {}" + ).format(str(remainders))) + self.launch_context.launch_args.extend(remainders) + + def python_executable(self): + """Should lead to python executable.""" + # TODO change in Pype 3 + return os.environ["PYPE_PYTHON_EXE"] From 7174dc16ef7f3e461902bb0590cbd90ce6f56411 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 10:16:03 +0100 Subject: [PATCH 031/279] added unreal prelaunch hook --- pype/hooks/unreal/pre_workfile_preparation.py | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 pype/hooks/unreal/pre_workfile_preparation.py diff --git a/pype/hooks/unreal/pre_workfile_preparation.py b/pype/hooks/unreal/pre_workfile_preparation.py new file mode 100644 index 0000000000..f0e09669dc --- /dev/null +++ b/pype/hooks/unreal/pre_workfile_preparation.py @@ -0,0 +1,95 @@ +import os + +from pype.lib import ( + PreLaunchHook, + ApplicationLaunchFailed +) +from pype.hosts.unreal import lib as unreal_lib + + +class UnrealPrelaunchHook(PreLaunchHook): + """ + This hook will check if current workfile path has Unreal + project inside. IF not, it initialize it and finally it pass + path to the project by environment variable to Unreal launcher + shell script. + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.signature = "( {} )".format(self.__class__.__name__) + + def execute(self): + asset_name = self.data["asset_name"] + task_name = self.data["task_name"] + workdir = self.env["AVALON_WORKDIR"] + engine_version = self.app_name.split("_")[-1] + unreal_project_name = f"{asset_name}_{task_name}" + + # Unreal is sensitive about project names longer then 20 chars + if len(unreal_project_name) > 20: + self.log.warning(( + f"Project name exceed 20 characters ({unreal_project_name})!" + )) + + # Unreal doesn't accept non alphabet characters at the start + # of the project name. This is because project name is then used + # in various places inside c++ code and there variable names cannot + # start with non-alpha. We append 'P' before project name to solve it. + # 😱 + if not unreal_project_name[:1].isalpha(): + self.log.warning(( + "Project name doesn't start with alphabet " + f"character ({unreal_project_name}). Appending 'P'" + )) + unreal_project_name = f"P{unreal_project_name}" + + project_path = os.path.join(workdir, unreal_project_name) + + self.log.info(( + f"{self.signature} requested UE4 version: " + f"[ {engine_version} ]" + )) + + detected = unreal_lib.get_engine_versions() + detected_str = ', '.join(detected.keys()) or 'none' + self.log.info(( + f"{self.signature} detected UE4 versions: " + f"[ {detected_str} ]" + )) + + engine_version = ".".join(engine_version.split(".")[:2]) + if engine_version not in detected.keys(): + raise ApplicationLaunchFailed(( + f"{self.signature} requested version not " + f"detected [ {engine_version} ]" + )) + + os.makedirs(project_path, exist_ok=True) + + project_file = os.path.join( + project_path, + f"{unreal_project_name}.uproject" + ) + if not os.path.isfile(project_file): + engine_path = detected[engine_version] + self.log.info(( + f"{self.signature} creating unreal " + f"project [ {unreal_project_name} ]" + )) + # Set "AVALON_UNREAL_PLUGIN" to current process environment for + # execution of `create_unreal_project` + env_key = "AVALON_UNREAL_PLUGIN" + if self.env.get(env_key): + os.environ[env_key] = self.env[env_key] + + unreal_lib.create_unreal_project( + unreal_project_name, + engine_version, + project_path, + engine_path=engine_path + ) + + # Append project file to launch arguments + self.launch_context.launch_args.append(f"\"{project_file}\"") From cc70fd75524a7fe2a34c8f6f6b0f9a50c28994d4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 10:50:03 +0100 Subject: [PATCH 032/279] ftrack sync can use application manager for applications sync --- pype/modules/ftrack/lib/avalon_sync.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/pype/modules/ftrack/lib/avalon_sync.py b/pype/modules/ftrack/lib/avalon_sync.py index 7ff5283d6a..97116317af 100644 --- a/pype/modules/ftrack/lib/avalon_sync.py +++ b/pype/modules/ftrack/lib/avalon_sync.py @@ -17,7 +17,10 @@ from bson.errors import InvalidId from pymongo import UpdateOne import ftrack_api from pype.api import config - +from pype.lib import ( + ApplicationManager, + env_value_to_bool +) log = Logger().get_logger(__name__) @@ -186,12 +189,28 @@ def get_project_apps(in_app_list): dictionary of warnings """ apps = [] + warnings = collections.defaultdict(list) + + if env_value_to_bool("PYPE_USE_APP_MANAGER", default=False): + missing_app_msg = "Missing definition of application" + application_manager = ApplicationManager() + for app_name in in_app_list: + app = application_manager.applications.get(app_name) + if app: + apps.append({ + "name": app_name, + "label": app.full_label + }) + else: + warnings[missing_app_msg].append(app_name) + return apps, warnings + # TODO report missing_toml_msg = "Missing config file for application" error_msg = ( "Unexpected error happend during preparation of application" ) - warnings = collections.defaultdict(list) + for app in in_app_list: try: toml_path = avalon.lib.which_app(app) From 0de4a563eeef70bbc7b712f8872cbb491cb3eb9b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 10:50:26 +0100 Subject: [PATCH 033/279] added TVPaint to applications --- .../system_settings/global/applications.json | 49 +++++++++++++++++++ .../host_settings/schema_tvpaint.json | 41 ++++++++++++++++ .../system_schema/schema_applications.json | 4 ++ 3 files changed, 94 insertions(+) create mode 100644 pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_tvpaint.json diff --git a/pype/settings/defaults/system_settings/global/applications.json b/pype/settings/defaults/system_settings/global/applications.json index 4bcea2fa30..d6ab2d7829 100644 --- a/pype/settings/defaults/system_settings/global/applications.json +++ b/pype/settings/defaults/system_settings/global/applications.json @@ -855,6 +855,55 @@ } } }, + "tvpaint": { + "enabled": true, + "label": "TVPaint", + "icon": "{}/app_icons/tvpaint.png", + "is_host": true, + "environment": { + "__environment_keys__": { + "tvpaint": [] + } + }, + "variants": { + "tvpaint_Animation 11 (64bits)": { + "enabled": true, + "label": "", + "variant_label": "Animation 11 (64bits)", + "icon": "", + "executables": { + "windows": [ + "C:\\Program Files\\TVPaint Developpement\\TVPaint Animation 11 (64bits)\\TVPaint Animation 11 (64bits).exe" + ], + "darwin": [], + "linux": [] + }, + "environment": { + "__environment_keys__": { + "tvpaint_Animation 11 (64bits)": [] + } + } + }, + "tvpaint_Animation 11 (32bits)": { + "enabled": true, + "label": "", + "variant_label": "Animation 11 (32bits)", + "icon": "", + "executables": { + "windows": [ + "C:\\Program Files (x86)\\TVPaint Developpement\\TVPaint Animation 11 (32bits)\\TVPaint Animation 11 (32bits).exe" + ], + "darwin": [], + "linux": [] + }, + "environment": { + "__environment_keys__": { + "tvpaint_Animation 11 (32bits)": [] + } + } + } + } + }, "photoshop": { "enabled": true, "label": "Adobe Photoshop", diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_tvpaint.json b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_tvpaint.json new file mode 100644 index 0000000000..09e5b1d907 --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_tvpaint.json @@ -0,0 +1,41 @@ +{ + "type": "dict", + "key": "tvpaint", + "label": "TVPaint", + "collapsable": true, + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "schema_template", + "name": "template_host_unchangables" + }, + { + "key": "environment", + "label": "Environment", + "type": "raw-json", + "env_group_key": "tvpaint" + }, + { + "type": "dict-invisible", + "key": "variants", + "children": [{ + "type": "schema_template", + "name": "template_host_variant", + "template_data": [ + { + "host_version": "Animation 11 (64bits)", + "host_name": "tvpaint" + }, + { + "host_version": "Animation 11 (32bits)", + "host_name": "tvpaint" + } + ] + }] + } + ] +} diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/schema_applications.json b/pype/tools/settings/settings/gui_schemas/system_schema/schema_applications.json index ebfa4482bb..65cd16049e 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/schema_applications.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/schema_applications.json @@ -65,6 +65,10 @@ "type": "schema", "name": "schema_harmony" }, + { + "type": "schema", + "name": "schema_tvpaint" + }, { "type": "schema", "name": "schema_photoshop" From 9ff8366ca44f9d05a52b53af802ed28f0eb00a35 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 11:33:38 +0100 Subject: [PATCH 034/279] use different loading for python 3 --- pype/lib/python_module_tools.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/pype/lib/python_module_tools.py b/pype/lib/python_module_tools.py index 61a3b1b09e..2ce2f60dca 100644 --- a/pype/lib/python_module_tools.py +++ b/pype/lib/python_module_tools.py @@ -1,9 +1,12 @@ import os +import sys import types +import importlib import inspect import logging log = logging.getLogger(__name__) +PY3 = sys.version_info[0] == 3 def modules_from_path(folder_path): @@ -39,11 +42,20 @@ def modules_from_path(folder_path): try: # Prepare module object where content of file will be parsed module = types.ModuleType(mod_name) - module.__file__ = full_path - with open(full_path) as _stream: - # Execute content and store it to module object - exec(_stream.read(), module.__dict__) + if PY3: + # Use loader so module has full specs + module_loader = importlib.machinery.SourceFileLoader( + mod_name, full_path + ) + module_loader.exec_module(module) + else: + # Execute module code and store content to module + with open(full_path) as _stream: + # Execute content and store it to module object + exec(_stream.read(), module.__dict__) + + module.__file__ = full_path modules.append(module) From 80a12c808e42de3ba281c1de83739734b13e6202 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 11:40:31 +0100 Subject: [PATCH 035/279] fix key error --- pype/hooks/celaction/pre_celaction_registers.py | 2 +- pype/hooks/tvpaint/pre_launch_args.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/hooks/celaction/pre_celaction_registers.py b/pype/hooks/celaction/pre_celaction_registers.py index c638ce3c0b..b65deda7f5 100644 --- a/pype/hooks/celaction/pre_celaction_registers.py +++ b/pype/hooks/celaction/pre_celaction_registers.py @@ -91,7 +91,7 @@ class CelactionPrelaunchHook(PreLaunchHook): winreg.SetValueEx(hKey, "Valid", 0, winreg.REG_DWORD, 1) def workfile_path(self): - workfile_path = self.data["last_workfile"] + workfile_path = self.data["last_workfile_path"] # copy workfile from template if doesnt exist any on path if not os.path.exists(workfile_path): diff --git a/pype/hooks/tvpaint/pre_launch_args.py b/pype/hooks/tvpaint/pre_launch_args.py index 6c59a8ce20..1901041d94 100644 --- a/pype/hooks/tvpaint/pre_launch_args.py +++ b/pype/hooks/tvpaint/pre_launch_args.py @@ -67,7 +67,7 @@ class TvpaintPrelaunchHook(PreLaunchHook): return script_path def workfile_path(self): - workfile_path = self.data["last_workfile"] + workfile_path = self.data["last_workfile_path"] # copy workfile from template if doesnt exist any on path if not os.path.exists(workfile_path): From a40279d4567d0b2fff72e7b409a37902083d5154 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 11:50:45 +0100 Subject: [PATCH 036/279] fix minor clean arguments bug --- pype/lib/applications.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pype/lib/applications.py b/pype/lib/applications.py index 9d34a8b22c..c1c6fc9301 100644 --- a/pype/lib/applications.py +++ b/pype/lib/applications.py @@ -1041,7 +1041,9 @@ class ApplicationLaunchContext: # Prepare subprocess args args = self.clear_launch_args(self.launch_args) self.log.debug( - "Launching \"{}\" with args: {}".format(self.app_name, args) + "Launching \"{}\" with args ({}): {}".format( + self.app_name, len(args), args + ) ) # Run process self.process = subprocess.Popen(args, **self.kwargs) @@ -1095,7 +1097,7 @@ class ApplicationLaunchContext: for _arg in arg: new_args.append(_arg) else: - new_args.append(args) + new_args.append(arg) args = new_args if all_cleared: From 92d34a0a66bc778f98e12192970f0c9dc92197e5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 13:18:51 +0100 Subject: [PATCH 037/279] fixed tvpaint launch --- pype/hooks/tvpaint/pre_launch_args.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/pype/hooks/tvpaint/pre_launch_args.py b/pype/hooks/tvpaint/pre_launch_args.py index 1901041d94..60ddcb6167 100644 --- a/pype/hooks/tvpaint/pre_launch_args.py +++ b/pype/hooks/tvpaint/pre_launch_args.py @@ -32,7 +32,7 @@ class TvpaintPrelaunchHook(PreLaunchHook): new_launch_args = [ self.main_executable(), - "\"{}\"".format(self.launch_script_path()), + self.launch_script_path(), "\"{}\"".format(tvpaint_executable) ] @@ -43,6 +43,15 @@ class TvpaintPrelaunchHook(PreLaunchHook): "\"{}\"".format(workfile_path) ) + # How to create new command line + # if platform.system().lower() == "windows": + # new_launch_args = [ + # "cmd.exe", + # "/c", + # "Call cmd.exe /k", + # *new_launch_args + # ] + # Append as whole list as these areguments should not be separated self.launch_context.launch_args.append(new_launch_args) @@ -55,7 +64,7 @@ class TvpaintPrelaunchHook(PreLaunchHook): def main_executable(self): """Should lead to python executable.""" # TODO change in Pype 3 - return os.environ["PYPE_PYTHON_EXE"] + return os.path.normpath(os.environ["PYPE_PYTHON_EXE"]) def launch_script_path(self): avalon_dir = os.path.dirname(os.path.abspath(avalon.__file__)) From 100dec2c7a9e4295caf980322825845f7b0e9ee7 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 25 Nov 2020 13:24:51 +0100 Subject: [PATCH 038/279] feat(imageio): adding default schema --- .../defaults/project_anatomy/{colorspace.json => imageio.json} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pype/settings/defaults/project_anatomy/{colorspace.json => imageio.json} (100%) diff --git a/pype/settings/defaults/project_anatomy/colorspace.json b/pype/settings/defaults/project_anatomy/imageio.json similarity index 100% rename from pype/settings/defaults/project_anatomy/colorspace.json rename to pype/settings/defaults/project_anatomy/imageio.json From 7df18a6b417c2897bb7d651a1d33c1b51f8e349e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 13:44:24 +0100 Subject: [PATCH 039/279] added imageio key to anatomy --- .../projects_schema/0_project_gui_schema.json | 3 ++ .../schema_anatomy_imageio.json | 8 +++++ .../settings/widgets/anatomy_types.py | 33 +++++++++++++++++-- 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/schema_anatomy_imageio.json diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json b/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json index cf95bf4c45..6f69340560 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json @@ -14,6 +14,9 @@ "type": "anatomy_templates", "key": "templates", "is_file": true + }, { + "type": "schema", + "name": "schema_anatomy_imageio" } ] }, { diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_anatomy_imageio.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_anatomy_imageio.json new file mode 100644 index 0000000000..3fdbd3f7f9 --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_anatomy_imageio.json @@ -0,0 +1,8 @@ +{ + "type": "dict", + "key": "imageio", + "label": "< ENTER LABEL HERE >", + "is_file": true, + "children": [ + ] +} diff --git a/pype/tools/settings/settings/widgets/anatomy_types.py b/pype/tools/settings/settings/widgets/anatomy_types.py index e1a726187c..ef89a802bc 100644 --- a/pype/tools/settings/settings/widgets/anatomy_types.py +++ b/pype/tools/settings/settings/widgets/anatomy_types.py @@ -1,7 +1,11 @@ from Qt import QtWidgets, QtCore from .widgets import ExpandingWidget from .item_types import ( - SettingObject, ModifiableDict, PathWidget, RawJsonWidget + SettingObject, + ModifiableDict, + PathWidget, + RawJsonWidget, + DictWidget ) from .lib import NOT_SET, TypeToKlass, CHILD_OFFSET, METADATA_KEY @@ -50,14 +54,18 @@ class AnatomyWidget(QtWidgets.QWidget, SettingObject): children_data = input_data["children"] roots_input_data = {} templates_input_data = {} + imageio_input_data = {} for child in children_data: if child["type"] == "anatomy_roots": roots_input_data = child elif child["type"] == "anatomy_templates": templates_input_data = child + elif child["key"] == "imageio": + imageio_input_data = child self.root_widget = RootsWidget(roots_input_data, self) self.templates_widget = TemplatesWidget(templates_input_data, self) + self.imageio_widget = DictWidget(imageio_input_data, self) self.setAttribute(QtCore.Qt.WA_StyledBackground) @@ -75,6 +83,7 @@ class AnatomyWidget(QtWidgets.QWidget, SettingObject): content_layout.addWidget(self.root_widget) content_layout.addWidget(self.templates_widget) + content_layout.addWidget(self.imageio_widget) body_widget.set_content_widget(content_widget) @@ -83,6 +92,7 @@ class AnatomyWidget(QtWidgets.QWidget, SettingObject): self.root_widget.value_changed.connect(self._on_value_change) self.templates_widget.value_changed.connect(self._on_value_change) + self.imageio_widget.value_changed.connect(self._on_value_change) def update_default_values(self, parent_values): self._state = None @@ -95,6 +105,7 @@ class AnatomyWidget(QtWidgets.QWidget, SettingObject): self.root_widget.update_default_values(value) self.templates_widget.update_default_values(value) + self.imageio_widget.update_default_values(value) def update_studio_values(self, parent_values): self._state = None @@ -107,6 +118,7 @@ class AnatomyWidget(QtWidgets.QWidget, SettingObject): self.root_widget.update_studio_values(value) self.templates_widget.update_studio_values(value) + self.imageio_widget.update_studio_values(value) def apply_overrides(self, parent_values): # Make sure this is set to False @@ -119,6 +131,7 @@ class AnatomyWidget(QtWidgets.QWidget, SettingObject): self.root_widget.apply_overrides(value) self.templates_widget.apply_overrides(value) + self.imageio_widget.apply_overrides(value) def set_value(self, value): raise TypeError("AnatomyWidget does not allow to use `set_value`") @@ -154,6 +167,7 @@ class AnatomyWidget(QtWidgets.QWidget, SettingObject): def hierarchical_style_update(self): self.root_widget.hierarchical_style_update() self.templates_widget.hierarchical_style_update() + self.imageio_widget.hierarchical_style_update() self.update_style() @property @@ -161,6 +175,7 @@ class AnatomyWidget(QtWidgets.QWidget, SettingObject): return ( self.root_widget.child_has_studio_override or self.templates_widget.child_has_studio_override + or self.imageio_widget.child_has_studio_override ) @property @@ -168,6 +183,7 @@ class AnatomyWidget(QtWidgets.QWidget, SettingObject): return ( self.root_widget.child_modified or self.templates_widget.child_modified + or self.imageio_widget.child_modified ) @property @@ -175,6 +191,7 @@ class AnatomyWidget(QtWidgets.QWidget, SettingObject): return ( self.root_widget.child_overriden or self.templates_widget.child_overriden + or self.imageio_widget.child_overriden ) @property @@ -182,27 +199,33 @@ class AnatomyWidget(QtWidgets.QWidget, SettingObject): return ( self.root_widget.child_invalid or self.templates_widget.child_invalid + or self.imageio_widget.child_invalid ) def set_as_overriden(self): self.root_widget.set_as_overriden() self.templates_widget.set_as_overriden() + self.imageio_widget.set_as_overriden() def remove_overrides(self): self.root_widget.remove_overrides() self.templates_widget.remove_overrides() + self.imageio_widget.remove_overrides() def reset_to_pype_default(self): self.root_widget.reset_to_pype_default() self.templates_widget.reset_to_pype_default() + self.imageio_widget.reset_to_pype_default() def set_studio_default(self): self.root_widget.set_studio_default() self.templates_widget.set_studio_default() + self.imageio_widget.set_studio_default() def discard_changes(self): self.root_widget.discard_changes() self.templates_widget.discard_changes() + self.imageio_widget.discard_changes() def overrides(self): if self.child_overriden: @@ -213,14 +236,20 @@ class AnatomyWidget(QtWidgets.QWidget, SettingObject): output = {} output.update(self.root_widget.config_value()) output.update(self.templates_widget.config_value()) + output.update(self.imageio_widget.config_value()) return output def studio_overrides(self): if ( self.root_widget.child_has_studio_override or self.templates_widget.child_has_studio_override + or self.imageio_widget.child_has_studio_override ): - groups = [self.root_widget.key, self.templates_widget.key] + groups = [ + self.root_widget.key, + self.templates_widget.key, + self.imageio_widget.key + ] value = self.config_value() value[self.key][METADATA_KEY] = {"groups": groups} return value, True From 674f287fe17f476991dcfff4fd718385366314d0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 13:53:08 +0100 Subject: [PATCH 040/279] change harmony and photoshop args --- pype/hooks/harmony/pre_launch_args.py | 16 +++++++--------- pype/hooks/photoshop/pre_launch_args.py | 17 ++++++++--------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/pype/hooks/harmony/pre_launch_args.py b/pype/hooks/harmony/pre_launch_args.py index 7047e67616..eabe1e6f87 100644 --- a/pype/hooks/harmony/pre_launch_args.py +++ b/pype/hooks/harmony/pre_launch_args.py @@ -21,7 +21,7 @@ class HarmonyPrelaunchHook(PreLaunchHook): while self.launch_context.launch_args: remainders.append(self.launch_context.launch_args.pop(0)) - python_launch_args = [ + new_launch_args = [ self.python_executable(), "-c", ( @@ -29,14 +29,12 @@ class HarmonyPrelaunchHook(PreLaunchHook): "avalon.harmony.launch(\"{}\")^\"\"" ).format(photoshop_executable) ] - if platform.system().lower() != "windows": - new_launch_args = python_launch_args - else: - new_launch_args = [ - "cmd.exe", - "/k", - "\"{}\"".format(" ".join(python_launch_args)) - ] + # if platform.system().lower() == "windows": + # new_launch_args = [ + # "cmd.exe", + # "/k", + # "\"{}\"".format(" ".join(new_launch_args)) + # ] # Append as whole list as these areguments should not be separated self.launch_context.launch_args.append(new_launch_args) diff --git a/pype/hooks/photoshop/pre_launch_args.py b/pype/hooks/photoshop/pre_launch_args.py index bc747dc495..77449a8269 100644 --- a/pype/hooks/photoshop/pre_launch_args.py +++ b/pype/hooks/photoshop/pre_launch_args.py @@ -21,7 +21,7 @@ class PhotoshopPrelaunchHook(PreLaunchHook): while self.launch_context.launch_args: remainders.append(self.launch_context.launch_args.pop(0)) - python_launch_args = [ + new_launch_args = [ self.python_executable(), "-c", ( @@ -29,14 +29,13 @@ class PhotoshopPrelaunchHook(PreLaunchHook): "avalon.photoshop.launch(\"{}\")^\"\"" ).format(photoshop_executable) ] - if platform.system().lower() != "windows": - new_launch_args = python_launch_args - else: - new_launch_args = [ - "cmd.exe", - "/k", - "\"{}\"".format(" ".join(python_launch_args)) - ] + + # if platform.system().lower() == "windows": + # new_launch_args = [ + # "cmd.exe", + # "/k", + # "\"{}\"".format(" ".join(new_launch_args)) + # ] # Append as whole list as these areguments should not be separated self.launch_context.launch_args.append(new_launch_args) From 75e1cadc31b5525a2583f1e71d9339066ec75006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Wed, 25 Nov 2020 14:02:06 +0100 Subject: [PATCH 041/279] help 4.26 unreal to create projects --- pype/hosts/unreal/lib.py | 19 +++++++++++-------- pype/lib/hooks.py | 2 +- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/pype/hosts/unreal/lib.py b/pype/hosts/unreal/lib.py index 5534c0cbc8..d6bfba436e 100644 --- a/pype/hosts/unreal/lib.py +++ b/pype/hosts/unreal/lib.py @@ -246,15 +246,18 @@ def create_unreal_project(project_name: str, with open(project_file, mode="w") as pf: json.dump(data, pf, indent=4) - # ensure we have PySide installed in engine - # TODO: make it work for other platforms 🍎 🐧 - if platform.system().lower() == "windows": - python_path = os.path.join(engine_path, "Engine", "Binaries", - "ThirdParty", "Python", "Win64", - "python.exe") + # UE < 4.26 have Python2 by default, so we need PySide + # but we will not need it in 4.26 and up + if int(ue_version.split(".")[1]) < 26: + # ensure we have PySide installed in engine + # TODO: make it work for other platforms 🍎 🐧 + if platform.system().lower() == "windows": + python_path = os.path.join(engine_path, "Engine", "Binaries", + "ThirdParty", "Python", "Win64", + "python.exe") - subprocess.run([python_path, "-m", - "pip", "install", "pyside"]) + subprocess.run([python_path, "-m", + "pip", "install", "pyside"]) if dev_mode or preset["dev_mode"]: _prepare_cpp_project(project_file, engine_path) diff --git a/pype/lib/hooks.py b/pype/lib/hooks.py index 425ad36342..bb5406572e 100644 --- a/pype/lib/hooks.py +++ b/pype/lib/hooks.py @@ -55,7 +55,7 @@ def execute_hook(hook, *args, **kwargs): module.__file__ = abspath try: - with open(abspath) as f: + with open(abspath, errors='ignore') as f: six.exec_(f.read(), module.__dict__) sys.modules[abspath] = module From da1a6ab320b687210c347048a6d1d45e9eb2b812 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 14:24:32 +0100 Subject: [PATCH 042/279] changed env groups in example to not match system env groups --- .../gui_schemas/system_schema/example_schema.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/example_schema.json b/pype/tools/settings/settings/gui_schemas/system_schema/example_schema.json index 7612e54116..f09ad86a65 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/example_schema.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/example_schema.json @@ -13,16 +13,16 @@ "type": "schema_template", "name": "example_template", "template_data": { - "host_label": "Maya 2019", - "host_name": "maya_2019", + "host_label": "Application 1", + "host_name": "app_1", "multipath_executables": false } }, { "type": "schema_template", "name": "example_template", "template_data": { - "host_label": "Maya 2020", - "host_name": "maya_2020" + "host_label": "Application 2", + "host_name": "app_2" } } ] From fc248c5eebe350924cd4d0ce29e14248dfb3e975 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 25 Nov 2020 14:27:27 +0100 Subject: [PATCH 043/279] test example schemas --- .../settings/gui_schemas/system_schema/schema_main.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/schema_main.json b/pype/tools/settings/settings/gui_schemas/system_schema/schema_main.json index 8e8798149c..3ec652c302 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/schema_main.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/schema_main.json @@ -17,6 +17,9 @@ }, { "type": "schema", "name": "schema_tools" + }, { + "type": "schema", + "name": "example_schema" }] } ] From 4c990a7527d14e6f2dfdb4eae3b95a3189060496 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 14:42:04 +0100 Subject: [PATCH 044/279] fixed validation of ListStrictWidget --- pype/tools/settings/settings/widgets/base.py | 2 +- pype/tools/settings/settings/widgets/item_types.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index 3f842602ca..692de617df 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -795,7 +795,7 @@ class ProjectWidget(QtWidgets.QWidget): def _update_values(self): self.ignore_value_changes = True - default_values = default_values = lib.convert_data_to_gui_data( + default_values = lib.convert_data_to_gui_data( {"project": default_settings()} ) for input_field in self.input_fields: diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index fd5364ea17..10fd757d3e 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1897,8 +1897,6 @@ class ListStrictWidget(QtWidgets.QWidget, InputObject): return self._default_input_value def set_value(self, value): - self.validate_value(value) - if self._is_overriden: method_name = "apply_overrides" elif not self._has_studio_override: From e1c9cd637bd92b867394fc1a031c138e4680b00c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 14:55:27 +0100 Subject: [PATCH 045/279] fix launch args --- pype/hooks/tvpaint/pre_launch_args.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/hooks/tvpaint/pre_launch_args.py b/pype/hooks/tvpaint/pre_launch_args.py index 60ddcb6167..7a5acb08fa 100644 --- a/pype/hooks/tvpaint/pre_launch_args.py +++ b/pype/hooks/tvpaint/pre_launch_args.py @@ -33,7 +33,7 @@ class TvpaintPrelaunchHook(PreLaunchHook): new_launch_args = [ self.main_executable(), self.launch_script_path(), - "\"{}\"".format(tvpaint_executable) + tvpaint_executable ] # Add workfile to launch arguments From 7e68d5b6498daa93c92025244fc6a7d80381bb39 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 15:49:23 +0100 Subject: [PATCH 046/279] hound cleanups --- pype/hooks/harmony/pre_launch_args.py | 1 - pype/hooks/photoshop/pre_launch_args.py | 1 - pype/hooks/tvpaint/pre_install_pywin.py | 3 ++- pype/hooks/tvpaint/pre_launch_args.py | 7 ++----- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/pype/hooks/harmony/pre_launch_args.py b/pype/hooks/harmony/pre_launch_args.py index eabe1e6f87..cafb2a4c60 100644 --- a/pype/hooks/harmony/pre_launch_args.py +++ b/pype/hooks/harmony/pre_launch_args.py @@ -1,5 +1,4 @@ import os -import platform from pype.lib import PreLaunchHook diff --git a/pype/hooks/photoshop/pre_launch_args.py b/pype/hooks/photoshop/pre_launch_args.py index 77449a8269..5b326f882b 100644 --- a/pype/hooks/photoshop/pre_launch_args.py +++ b/pype/hooks/photoshop/pre_launch_args.py @@ -1,5 +1,4 @@ import os -import platform from pype.lib import PreLaunchHook diff --git a/pype/hooks/tvpaint/pre_install_pywin.py b/pype/hooks/tvpaint/pre_install_pywin.py index 20d4b2aae7..b51267934b 100644 --- a/pype/hooks/tvpaint/pre_install_pywin.py +++ b/pype/hooks/tvpaint/pre_install_pywin.py @@ -26,8 +26,9 @@ class PreInstallPyWin(PreLaunchHook): try: output = _subprocess( - ["pip", "install", "pywin32==227"], logger=self.log + ["pip", "install", "pywin32==227"] ) + self.log.debug("Pip install pywin32 output:\n{}'".format(output)) except RuntimeError: msg = "Installation of python module `pywin32` crashed." self.log.warning(msg, exc_info=True) diff --git a/pype/hooks/tvpaint/pre_launch_args.py b/pype/hooks/tvpaint/pre_launch_args.py index 7a5acb08fa..9d80e6fddb 100644 --- a/pype/hooks/tvpaint/pre_launch_args.py +++ b/pype/hooks/tvpaint/pre_launch_args.py @@ -2,11 +2,8 @@ import os import shutil from pype.hosts import tvpaint -from pype.lib import ( - PreLaunchHook, - ApplicationLaunchFailed, - _subprocess -) +from pype.lib import PreLaunchHook + import avalon From c77946c181838c8dfa99b932ecd256f86967ad08 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 15:52:15 +0100 Subject: [PATCH 047/279] added aftereffects prelaunch hook --- pype/hooks/aftereffects/pre_launch_args.py | 45 ++++++++++++++++++++++ pype/hooks/harmony/pre_launch_args.py | 6 --- pype/hooks/photoshop/pre_launch_args.py | 7 ---- 3 files changed, 45 insertions(+), 13 deletions(-) create mode 100644 pype/hooks/aftereffects/pre_launch_args.py diff --git a/pype/hooks/aftereffects/pre_launch_args.py b/pype/hooks/aftereffects/pre_launch_args.py new file mode 100644 index 0000000000..9bd3a41ee4 --- /dev/null +++ b/pype/hooks/aftereffects/pre_launch_args.py @@ -0,0 +1,45 @@ +import os + +from pype.lib import PreLaunchHook + + +class AfterEffectsPrelaunchHook(PreLaunchHook): + """Launch arguments preparation. + + Hook add python executable and execute python script of AfterEffects + implementation before AfterEffects executable. + """ + hosts = ["aftereffects"] + + def execute(self): + # Pop tvpaint executable + photoshop_executable = self.launch_context.launch_args.pop(0) + + # Pop rest of launch arguments - There should not be other arguments! + remainders = [] + while self.launch_context.launch_args: + remainders.append(self.launch_context.launch_args.pop(0)) + + new_launch_args = [ + self.python_executable(), + "-c", + ( + "^\"import avalon.aftereffects;" + "avalon.aftereffects.launch(\"{}\")^\"\"" + ).format(photoshop_executable) + ] + + # Append as whole list as these areguments should not be separated + self.launch_context.launch_args.append(new_launch_args) + + if remainders: + self.log.warning(( + "There are unexpected launch arguments " + "in AfterEffects launch. {}" + ).format(str(remainders))) + self.launch_context.launch_args.extend(remainders) + + def python_executable(self): + """Should lead to python executable.""" + # TODO change in Pype 3 + return os.environ["PYPE_PYTHON_EXE"] diff --git a/pype/hooks/harmony/pre_launch_args.py b/pype/hooks/harmony/pre_launch_args.py index cafb2a4c60..48a72d6ec9 100644 --- a/pype/hooks/harmony/pre_launch_args.py +++ b/pype/hooks/harmony/pre_launch_args.py @@ -28,12 +28,6 @@ class HarmonyPrelaunchHook(PreLaunchHook): "avalon.harmony.launch(\"{}\")^\"\"" ).format(photoshop_executable) ] - # if platform.system().lower() == "windows": - # new_launch_args = [ - # "cmd.exe", - # "/k", - # "\"{}\"".format(" ".join(new_launch_args)) - # ] # Append as whole list as these areguments should not be separated self.launch_context.launch_args.append(new_launch_args) diff --git a/pype/hooks/photoshop/pre_launch_args.py b/pype/hooks/photoshop/pre_launch_args.py index 5b326f882b..840e4e2a32 100644 --- a/pype/hooks/photoshop/pre_launch_args.py +++ b/pype/hooks/photoshop/pre_launch_args.py @@ -29,13 +29,6 @@ class PhotoshopPrelaunchHook(PreLaunchHook): ).format(photoshop_executable) ] - # if platform.system().lower() == "windows": - # new_launch_args = [ - # "cmd.exe", - # "/k", - # "\"{}\"".format(" ".join(new_launch_args)) - # ] - # Append as whole list as these areguments should not be separated self.launch_context.launch_args.append(new_launch_args) From 576c359b4ff8de3445babbcf46c1f6817580268d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 15:56:55 +0100 Subject: [PATCH 048/279] added aftereffects to application schemas --- .../system_settings/global/applications.json | 67 ++++++++++++++++++- .../host_settings/schema_aftereffects.json | 41 ++++++++++++ .../system_schema/schema_applications.json | 4 ++ 3 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_aftereffects.json diff --git a/pype/settings/defaults/system_settings/global/applications.json b/pype/settings/defaults/system_settings/global/applications.json index d6ab2d7829..3eda5e036d 100644 --- a/pype/settings/defaults/system_settings/global/applications.json +++ b/pype/settings/defaults/system_settings/global/applications.json @@ -862,8 +862,11 @@ "is_host": true, "environment": { "__environment_keys__": { - "tvpaint": [] - } + "tvpaint": [ + "PYPE_LOG_NO_COLORS" + ] + }, + "PYPE_LOG_NO_COLORS": "True" }, "variants": { "tvpaint_Animation 11 (64bits)": { @@ -944,6 +947,66 @@ } } }, + "aftereffects": { + "enabled": true, + "label": "Adobe AfterEffects", + "icon": "{}/app_icons/aftereffects.png", + "is_host": true, + "environment": { + "__environment_keys__": { + "aftereffects": [ + "AVALON_AFTEREFFECTS_WORKFILES_ON_LAUNCH", + "PYTHONPATH", + "PYPE_LOG_NO_COLORS", + "WEBSOCKET_URL", + "WORKFILES_SAVE_AS" + ] + }, + "AVALON_AFTEREFFECTS_WORKFILES_ON_LAUNCH": "1", + "PYTHONPATH": "{PYTHONPATH}", + "PYPE_LOG_NO_COLORS": "Yes", + "WEBSOCKET_URL": "ws://localhost:8097/ws/", + "WORKFILES_SAVE_AS": "Yes" + }, + "variants": { + "aftereffects_2020": { + "enabled": true, + "label": "", + "variant_label": "2020", + "icon": "", + "executables": { + "windows": [ + "C:\\Program Files\\Adobe\\Adobe After Effects 2020\\Support Files\\AfterFX.exe" + ], + "darwin": [], + "linux": [] + }, + "environment": { + "__environment_keys__": { + "aftereffects_2020": [] + } + } + }, + "aftereffects_2021": { + "enabled": true, + "label": "", + "variant_label": "2021", + "icon": "", + "executables": { + "windows": [ + "C:\\Program Files\\Adobe\\Adobe After Effects 2021\\Support Files\\AfterFX.exe" + ], + "darwin": [], + "linux": [] + }, + "environment": { + "__environment_keys__": { + "aftereffects_2021": [] + } + } + } + } + }, "celaction": { "enabled": true, "label": "CelAction 2D", diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_aftereffects.json b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_aftereffects.json new file mode 100644 index 0000000000..073d57b870 --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_aftereffects.json @@ -0,0 +1,41 @@ +{ + "type": "dict", + "key": "aftereffects", + "label": "Adobe AfterEffects", + "collapsable": true, + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "schema_template", + "name": "template_host_unchangables" + }, + { + "key": "environment", + "label": "Environment", + "type": "raw-json", + "env_group_key": "aftereffects" + }, + { + "type": "dict-invisible", + "key": "variants", + "children": [{ + "type": "schema_template", + "name": "template_host_variant", + "template_data": [ + { + "host_version": "2020", + "host_name": "aftereffects" + }, + { + "host_version": "2021", + "host_name": "aftereffects" + } + ] + }] + } + ] +} diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/schema_applications.json b/pype/tools/settings/settings/gui_schemas/system_schema/schema_applications.json index 65cd16049e..1c983bcff2 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/schema_applications.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/schema_applications.json @@ -73,6 +73,10 @@ "type": "schema", "name": "schema_photoshop" }, + { + "type": "schema", + "name": "schema_aftereffects" + }, { "type": "schema", "name": "schema_celaction" From 5159d3dabdec93aaa3291578fd68f562f89ae000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= <33513211+antirotor@users.noreply.github.com> Date: Wed, 25 Nov 2020 15:58:58 +0100 Subject: [PATCH 049/279] Maya: Vray handling of default aov --- pype/hosts/maya/expected_files.py | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/pype/hosts/maya/expected_files.py b/pype/hosts/maya/expected_files.py index 8d225bc13d..05b0785251 100644 --- a/pype/hosts/maya/expected_files.py +++ b/pype/hosts/maya/expected_files.py @@ -561,24 +561,6 @@ class ExpectedFilesVray(AExpectedFiles): layer_data["padding"] = cmds.getAttr("vraySettings.fileNamePadding") return layer_data - def get_files(self): - """Get expected files. - - This overrides :func:`AExpectedFiles.get_files()` as we - we need to add one sequence for plain beauty if AOVs are enabled - as vray output beauty without 'beauty' in filename. - - """ - expected_files = super(ExpectedFilesVray, self).get_files() - - layer_data = self._get_layer_data() - if layer_data.get("enabledAOVs"): - expected_files[0][u"beauty"] = self._generate_single_file_sequence( - layer_data - ) # noqa: E501 - - return expected_files - def get_aovs(self): """Get all AOVs. @@ -630,6 +612,9 @@ class ExpectedFilesVray(AExpectedFiles): # todo: find how vray set format for AOVs enabled_aovs.append( (self._get_vray_aov_name(aov), default_ext)) + enabled_aovs.append( + (u"beauty", default_ext) + ) return enabled_aovs def _get_vray_aov_name(self, node): From 8f08412ec7f2129298b0409df417e27ba4b46e9d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 17:04:07 +0100 Subject: [PATCH 050/279] fixed python launch --- pype/hooks/aftereffects/pre_launch_args.py | 8 ++++---- pype/hooks/harmony/pre_launch_args.py | 8 ++++---- pype/hooks/photoshop/pre_launch_args.py | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pype/hooks/aftereffects/pre_launch_args.py b/pype/hooks/aftereffects/pre_launch_args.py index 9bd3a41ee4..01406d495c 100644 --- a/pype/hooks/aftereffects/pre_launch_args.py +++ b/pype/hooks/aftereffects/pre_launch_args.py @@ -13,7 +13,7 @@ class AfterEffectsPrelaunchHook(PreLaunchHook): def execute(self): # Pop tvpaint executable - photoshop_executable = self.launch_context.launch_args.pop(0) + aftereffects_executable = self.launch_context.launch_args.pop(0) # Pop rest of launch arguments - There should not be other arguments! remainders = [] @@ -24,9 +24,9 @@ class AfterEffectsPrelaunchHook(PreLaunchHook): self.python_executable(), "-c", ( - "^\"import avalon.aftereffects;" - "avalon.aftereffects.launch(\"{}\")^\"\"" - ).format(photoshop_executable) + "import avalon.aftereffects;" + "avalon.aftereffects.launch(\"{}\")" + ).format(aftereffects_executable) ] # Append as whole list as these areguments should not be separated diff --git a/pype/hooks/harmony/pre_launch_args.py b/pype/hooks/harmony/pre_launch_args.py index 48a72d6ec9..70fac5bb76 100644 --- a/pype/hooks/harmony/pre_launch_args.py +++ b/pype/hooks/harmony/pre_launch_args.py @@ -13,7 +13,7 @@ class HarmonyPrelaunchHook(PreLaunchHook): def execute(self): # Pop tvpaint executable - photoshop_executable = self.launch_context.launch_args.pop(0) + harmony_executable = self.launch_context.launch_args.pop(0) # Pop rest of launch arguments - There should not be other arguments! remainders = [] @@ -24,9 +24,9 @@ class HarmonyPrelaunchHook(PreLaunchHook): self.python_executable(), "-c", ( - "^\"import avalon.harmony;" - "avalon.harmony.launch(\"{}\")^\"\"" - ).format(photoshop_executable) + "import avalon.harmony;" + "avalon.harmony.launch(\"{}\")" + ).format(harmony_executable) ] # Append as whole list as these areguments should not be separated diff --git a/pype/hooks/photoshop/pre_launch_args.py b/pype/hooks/photoshop/pre_launch_args.py index 840e4e2a32..2c88f62157 100644 --- a/pype/hooks/photoshop/pre_launch_args.py +++ b/pype/hooks/photoshop/pre_launch_args.py @@ -24,8 +24,8 @@ class PhotoshopPrelaunchHook(PreLaunchHook): self.python_executable(), "-c", ( - "^\"import avalon.photoshop;" - "avalon.photoshop.launch(\"{}\")^\"\"" + "import avalon.photoshop;" + "avalon.photoshop.launch(\"{}\")" ).format(photoshop_executable) ] From ec0127c79a17fcf51a87c0d4658d744084ed3f01 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 17:06:10 +0100 Subject: [PATCH 051/279] added photoshop 2021 --- .../system_settings/global/applications.json | 22 ++++++++++++++++++- .../host_settings/schema_photoshop.json | 4 ++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/pype/settings/defaults/system_settings/global/applications.json b/pype/settings/defaults/system_settings/global/applications.json index 3eda5e036d..c638f1e3d2 100644 --- a/pype/settings/defaults/system_settings/global/applications.json +++ b/pype/settings/defaults/system_settings/global/applications.json @@ -935,7 +935,9 @@ "variant_label": "2020", "icon": "", "executables": { - "windows": [], + "windows": [ + "C:\\Program Files\\Adobe\\Adobe Photoshop 2020\\Photoshop.exe" + ], "darwin": [], "linux": [] }, @@ -944,6 +946,24 @@ "photoshop_2020": [] } } + }, + "photoshop_2021": { + "enabled": true, + "label": "", + "variant_label": "2021", + "icon": "", + "executables": { + "windows": [ + "C:\\Program Files\\Adobe\\Adobe Photoshop 2021\\Photoshop.exe" + ], + "darwin": [], + "linux": [] + }, + "environment": { + "__environment_keys__": { + "photoshop_2021": [] + } + } } } }, diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_photoshop.json b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_photoshop.json index f86f6ff055..0c27611b29 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_photoshop.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_photoshop.json @@ -29,6 +29,10 @@ { "host_version": "2020", "host_name": "photoshop" + }, + { + "host_version": "2021", + "host_name": "photoshop" } ] }] From 3b6eec2b5b6df5b88abb0398a14b7ab4e034020c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= <33513211+antirotor@users.noreply.github.com> Date: Wed, 25 Nov 2020 17:55:36 +0100 Subject: [PATCH 052/279] remove `_beauty` from vray output files --- pype/hosts/maya/expected_files.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/pype/hosts/maya/expected_files.py b/pype/hosts/maya/expected_files.py index 05b0785251..bd58b10d74 100644 --- a/pype/hosts/maya/expected_files.py +++ b/pype/hosts/maya/expected_files.py @@ -561,6 +561,30 @@ class ExpectedFilesVray(AExpectedFiles): layer_data["padding"] = cmds.getAttr("vraySettings.fileNamePadding") return layer_data + def get_files(self): + """Get expected files. + + This overrides :func:`AExpectedFiles.get_files()` as we + we need to add one sequence for plain beauty if AOVs are enabled + as vray output beauty without 'beauty' in filename. + + """ + expected_files = super(ExpectedFilesVray, self).get_files() + + layer_data = self._get_layer_data() + # remove 'beauty' from filenames as vray doesn't output it + update = {} + if layer_data.get("enabledAOVs"): + for aov, seq in expected_files[0].items(): + if aov.startswith("beauty"): + new_list = [] + for f in seq: + new_list.append(f.replace("_beauty", "")) + update[aov] = new_list + + expected_files[0].update(update) + return expected_files + def get_aovs(self): """Get all AOVs. From 342b3f80e9384ea5362a4add00eecf40e9610db3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 18:12:45 +0100 Subject: [PATCH 053/279] fixed collapsability --- .../settings/settings/widgets/item_types.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index fd5364ea17..4ba3be12cb 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2190,15 +2190,6 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.body_widget = body_widget self.label_widget = body_widget.label_widget - collapsable = input_data.get("collapsable", True) - if collapsable: - collapsed = input_data.get("collapsed", True) - if not collapsed: - body_widget.toggle_content() - - else: - body_widget.hide_toolbox(hide_content=False) - if body_widget is None: content_parent_widget = self else: @@ -2219,6 +2210,16 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.content_widget = content_widget self.content_layout = content_layout + if not as_widget: + collapsable = input_data.get("collapsable", True) + if collapsable: + collapsed = input_data.get("collapsed", True) + if not collapsed: + body_widget.toggle_content() + + else: + body_widget.hide_toolbox(hide_content=False) + self.setAttribute(QtCore.Qt.WA_TranslucentBackground) self.add_row(is_empty=True) From 3bb15ac9a5010b0870a570f18a8ec89fd8e86133 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 18:17:50 +0100 Subject: [PATCH 054/279] do not create expanding part if label is not entered --- pype/tools/settings/settings/widgets/item_types.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 4ba3be12cb..15ba817f29 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2180,9 +2180,16 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): main_layout.setContentsMargins(0, 0, 0, 0) main_layout.setSpacing(0) + label = input_data.get("label") + if as_widget: body_widget = None self.label_widget = label_widget + + elif label is None: + body_widget = None + self.body_widget = body_widget + self.label_widget = None else: body_widget = ExpandingWidget(input_data["label"], self) main_layout.addWidget(body_widget) @@ -2210,7 +2217,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.content_widget = content_widget self.content_layout = content_layout - if not as_widget: + if not as_widget and body_widget: collapsable = input_data.get("collapsable", True) if collapsable: collapsed = input_data.get("collapsed", True) From b3beb2baf120a9316f3fcfb9d6606a39bae54314 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Wed, 25 Nov 2020 18:22:13 +0100 Subject: [PATCH 055/279] start on ftrack settings --- .../ftrack/ftrack_custom_attributes.json | 56 --- .../ftrack/partnership_ftrack_cred.json | 5 - .../system_settings/global/modules.json | 12 +- .../projects_schema/0_project_gui_schema.json | 3 +- .../projects_schema/1_plugins_gui_schema.json | 326 ------------- .../schemas/schema_project_celaction.json | 50 ++ .../schemas/schema_project_ftrack.json | 129 ++++++ .../schemas/schema_project_hiero.json | 43 ++ .../schemas/schema_project_maya.json | 28 ++ .../schemas/schema_project_nuke.json | 140 ++++++ .../schemas/schema_project_resolve.json | 35 ++ .../module_settings/schema_ftrack.json | 147 ++++++ .../system_schema/schema_modules.json | 430 +++++++----------- 13 files changed, 745 insertions(+), 659 deletions(-) delete mode 100644 pype/settings/defaults/project_settings/ftrack/partnership_ftrack_cred.json create mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_celaction.json create mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_ftrack.json create mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_hiero.json create mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_maya.json create mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_nuke.json create mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_resolve.json create mode 100644 pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json diff --git a/pype/settings/defaults/project_settings/ftrack/ftrack_custom_attributes.json b/pype/settings/defaults/project_settings/ftrack/ftrack_custom_attributes.json index f03d473cd0..371be3b8d8 100644 --- a/pype/settings/defaults/project_settings/ftrack/ftrack_custom_attributes.json +++ b/pype/settings/defaults/project_settings/ftrack/ftrack_custom_attributes.json @@ -10,47 +10,6 @@ "config": { "isdecimal": true } -}, { - "label": "Applications", - "key": "applications", - "type": "enumerator", - "entity_type": "show", - "group": "avalon", - "config": { - "multiselect": true, - "data": [ - {"blender_2.80": "Blender 2.80"}, - {"blender_2.81": "Blender 2.81"}, - {"blender_2.82": "Blender 2.82"}, - {"blender_2.83": "Blender 2.83"}, - {"celaction_local": "CelAction2D Local"}, - {"maya_2017": "Maya 2017"}, - {"maya_2018": "Maya 2018"}, - {"maya_2019": "Maya 2019"}, - {"nuke_10.0": "Nuke 10.0"}, - {"nuke_11.2": "Nuke 11.2"}, - {"nuke_11.3": "Nuke 11.3"}, - {"nuke_12.0": "Nuke 12.0"}, - {"nukex_10.0": "NukeX 10.0"}, - {"nukex_11.2": "NukeX 11.2"}, - {"nukex_11.3": "NukeX 11.3"}, - {"nukex_12.0": "NukeX 12.0"}, - {"nukestudio_10.0": "NukeStudio 10.0"}, - {"nukestudio_11.2": "NukeStudio 11.2"}, - {"nukestudio_11.3": "NukeStudio 11.3"}, - {"nukestudio_12.0": "NukeStudio 12.0"}, - {"harmony_17": "Harmony 17"}, - {"houdini_16.5": "Houdini 16.5"}, - {"houdini_17": "Houdini 17"}, - {"houdini_18": "Houdini 18"}, - {"photoshop_2020": "Photoshop 2020"}, - {"python_3": "Python 3"}, - {"python_2": "Python 2"}, - {"premiere_2019": "Premiere Pro 2019"}, - {"premiere_2020": "Premiere Pro 2020"}, - {"resolve_16": "BM DaVinci Resolve 16"} - ] - } }, { "label": "Avalon auto-sync", "key": "avalon_auto_sync", @@ -109,21 +68,6 @@ "is_hierarchical": true, "group": "avalon", "default": null -}, { - "label": "Tools", - "key": "tools_env", - "type": "enumerator", - "is_hierarchical": true, - "group": "avalon", - "config": { - "multiselect": true, - "data": [ - {"mtoa_3.0.1": "mtoa_3.0.1"}, - {"mtoa_3.1.1": "mtoa_3.1.1"}, - {"mtoa_3.2.0": "mtoa_3.2.0"}, - {"yeti_2.1.2": "yeti_2.1"} - ] - } }, { "label": "Resolution Width", "key": "resolutionWidth", diff --git a/pype/settings/defaults/project_settings/ftrack/partnership_ftrack_cred.json b/pype/settings/defaults/project_settings/ftrack/partnership_ftrack_cred.json deleted file mode 100644 index 6b3a32f181..0000000000 --- a/pype/settings/defaults/project_settings/ftrack/partnership_ftrack_cred.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "server_url": "", - "api_key": "", - "api_user": "" -} diff --git a/pype/settings/defaults/system_settings/global/modules.json b/pype/settings/defaults/system_settings/global/modules.json index a28c2f4a03..6c7a45cca3 100644 --- a/pype/settings/defaults/system_settings/global/modules.json +++ b/pype/settings/defaults/system_settings/global/modules.json @@ -27,11 +27,13 @@ "ftrack_events_path": [], "FTRACK_EVENTS_MONGO_DB": "pype", "FTRACK_EVENTS_MONGO_COL": "ftrack_events", - "sync_to_avalon": { - "statuses_name_change": [ - "ready", - "not ready" - ] + "events": { + "sync_to_avalon": { + "enabled": true, + "statuses_name_change": [ + "not ready" + ] + } }, "status_version_to_task": {}, "status_update": { diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json b/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json index cf95bf4c45..5b19a1159a 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json @@ -16,7 +16,8 @@ "is_file": true } ] - }, { + }, + { "type": "dict-invisible", "key": "project_settings", "children": [ diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/1_plugins_gui_schema.json b/pype/tools/settings/settings/gui_schemas/projects_schema/1_plugins_gui_schema.json index 87912cfdc0..0ccdd79bc7 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/1_plugins_gui_schema.json @@ -4,89 +4,6 @@ "key": "plugins", "label": "Plugins", "children": [{ - "type": "dict", - "collapsable": true, - "key": "celaction", - "label": "CelAction", - "children": [{ - "type": "dict", - "collapsable": true, - "key": "publish", - "label": "Publish plugins", - "is_file": true, - "children": [{ - "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "ExtractCelactionDeadline", - "label": "ExtractCelactionDeadline", - "is_group": true, - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "text", - "key": "deadline_department", - "label": "Deadline apartment" - }, { - "type": "number", - "key": "deadline_priority", - "label": "Deadline priority" - }, { - "type": "text", - "key": "deadline_pool", - "label": "Deadline pool" - }, { - "type": "text", - "key": "deadline_pool_secondary", - "label": "Deadline pool (secondary)" - }, { - "type": "text", - "key": "deadline_group", - "label": "Deadline Group" - }, { - "type": "number", - "key": "deadline_chunk_size", - "label": "Deadline Chunk size" - }] - }] - }] - }, { - "type": "dict", - "collapsable": true, - "key": "ftrack", - "label": "Ftrack", - "children": [{ - "type": "dict", - "collapsable": true, - "key": "publish", - "label": "Publish plugins", - "is_file": true, - "children": [{ - "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "IntegrateFtrackNote", - "label": "IntegrateFtrackNote", - "is_group": true, - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "text", - "key": "note_with_intent_template", - "label": "Note with intent template" - }, { - "type": "list", - "object_type": "text", - "key": "note_labels", - "label": "Note labels" - }] - }] - }] - }, { "type": "dict", "collapsable": true, "key": "global", @@ -327,249 +244,6 @@ }] }] }] - }, { - "type": "dict-invisible", - "collapsable": true, - "key": "maya", - "label": "Maya", - "children": [{ - "type": "dict", - "collapsable": true, - "key": "maya", - "label": "Maya", - "children": [ - - { - "type": "schema", - "name": "2_maya_capture" - }, - { - "type": "schema", - "name": "2_maya_plugins" - }, - { - "type": "schema", - "name": "2_maya_workfiles" - } - ] - }] - }, { - "type": "dict", - "collapsable": true, - "key": "nuke", - "label": "Nuke", - "children": [{ - "type": "dict", - "collapsable": true, - "key": "create", - "label": "Create plugins", - "is_file": true, - "children": [{ - "type": "dict", - "collapsable": false, - "key": "CreateWriteRender", - "label": "CreateWriteRender", - "is_group": true, - "children": [{ - "type": "text", - "key": "fpath_template", - "label": "Path template" - }] - }, { - "type": "dict", - "collapsable": false, - "key": "CreateWritePrerender", - "label": "CreateWritePrerender", - "is_group": true, - "children": [{ - "type": "text", - "key": "fpath_template", - "label": "Path template" - }] - }] - }, { - "type": "dict", - "collapsable": true, - "key": "publish", - "label": "Publish plugins", - "is_file": true, - "children": [{ - "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "ExtractThumbnail", - "label": "ExtractThumbnail", - "is_group": true, - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "raw-json", - "key": "nodes", - "label": "Nodes" - }] - }, { - "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "ValidateNukeWriteKnobs", - "label": "ValidateNukeWriteKnobs", - "is_group": true, - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "raw-json", - "key": "knobs", - "label": "Knobs" - }] - }, { - "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "ExtractReviewDataLut", - "label": "ExtractReviewDataLut", - "is_group": true, - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }] - }, { - "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "ExtractReviewDataMov", - "label": "ExtractReviewDataMov", - "is_group": true, - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "boolean", - "key": "viewer_lut_raw", - "label": "Viewer LUT raw" - }] - }, { - "type": "dict", - "collapsable": true, - "key": "ExtractSlateFrame", - "label": "ExtractSlateFrame", - "is_group": true, - "children": [{ - "type": "boolean", - "key": "viewer_lut_raw", - "label": "Viewer LUT raw" - }] - }, { - "type": "dict", - "collapsable": true, - "key": "NukeSubmitDeadline", - "label": "NukeSubmitDeadline", - "is_group": true, - "children": [{ - "type": "number", - "key": "deadline_priority", - "label": "deadline_priority" - }, { - "type": "text", - "key": "deadline_pool", - "label": "deadline_pool" - }, { - "type": "text", - "key": "deadline_pool_secondary", - "label": "deadline_pool_secondary" - }, { - "type": "number", - "key": "deadline_chunk_size", - "label": "deadline_chunk_size" - }] - }] - }, { - "type": "raw-json", - "key": "workfile_build", - "label": "Workfile Build logic", - "is_file": true - }] - }, { - "type": "dict", - "collapsable": true, - "key": "nukestudio", - "label": "NukeStudio", - "children": [{ - "type": "dict", - "collapsable": true, - "key": "publish", - "label": "Publish plugins", - "is_file": true, - "children": [{ - "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "CollectInstanceVersion", - "label": "Collect Instance Version", - "is_group": true, - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }] - }, { - "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "ExtractReviewCutUpVideo", - "label": "Extract Review Cut Up Video", - "is_group": true, - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "list", - "object_type": "text", - "key": "tags_addition", - "label": "Tags addition" - }] - }] - }] - }, { - "type": "dict", - "collapsable": true, - "key": "resolve", - "label": "DaVinci Resolve", - "children": [{ - "type": "dict", - "collapsable": true, - "key": "create", - "label": "Creator plugins", - "is_file": true, - "children": [{ - "type": "dict", - "collapsable": true, - "key": "CreateShotClip", - "label": "Create Shot Clip", - "is_group": true, - "children": [{ - "type": "text", - "key": "clipName", - "label": "Clip name template" - }, { - "type": "text", - "key": "folder", - "label": "Folder" - }, { - "type": "number", - "key": "steps", - "label": "Steps" - }] - } - - ] - }] }, { "type": "dict", diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_celaction.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_celaction.json new file mode 100644 index 0000000000..a1c94b14ef --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_celaction.json @@ -0,0 +1,50 @@ +{ + "type": "dict", + "collapsable": true, + "key": "celaction", + "label": "CelAction", + "is_file": true, + "children": [{ + "type": "dict", + "collapsable": true, + "key": "publish", + "label": "Publish plugins", + "children": [{ + "type": "dict", + "collapsable": true, + "checkbox_key": "enabled", + "key": "ExtractCelactionDeadline", + "label": "ExtractCelactionDeadline", + "is_group": true, + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "text", + "key": "deadline_department", + "label": "Deadline apartment" + }, { + "type": "number", + "key": "deadline_priority", + "label": "Deadline priority" + }, { + "type": "text", + "key": "deadline_pool", + "label": "Deadline pool" + }, { + "type": "text", + "key": "deadline_pool_secondary", + "label": "Deadline pool (secondary)" + }, { + "type": "text", + "key": "deadline_group", + "label": "Deadline Group" + }, { + "type": "number", + "key": "deadline_chunk_size", + "label": "Deadline Chunk size" + }] + }] + }] +} diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_ftrack.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_ftrack.json new file mode 100644 index 0000000000..1d6b4cbf5b --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_ftrack.json @@ -0,0 +1,129 @@ +{ + "type": "dict", + "key": "Ftrack", + "label": "Ftrack", + "collapsable": true, + "checkbox_key": "enabled", + "is_file": true, + "children": [ + { + "type": "splitter" + }, + { + "type": "label", + "label": "Additional Ftrack paths" + }, + { + "type": "list", + "key": "ftrack_actions_path", + "label": "Action paths", + "object_type": "text" + }, + { + "type": "list", + "key": "ftrack_events_path", + "label": "Event paths", + "object_type": "text" + }, + { + "type": "splitter" + }, + { + "type": "dict", + "key": "events", + "label": "Server Events", + "children": [{ + "type": "dict", + "key": "sync_to_avalon", + "label": "Sync to avalon", + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "list", + "key": "statuses_name_change", + "label": "Status name change", + "object_type": { + "type": "text", + "multiline": false + } + }] + }, + { + "type": "dict", + "key": "status_version_to_task", + "label": "Version to Task status mapping", + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "dict-modifiable", + "key": "statuses", + "label": "Stausesg", + "object_type": "text" + }] + }, + { + "type": "dict", + "key": "status_update", + "label": "Status Updates", + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "key": "statuses", + "type": "dict-invisible", + "children": [ + { + "key": "default", + "type": "text", + "label": "complete" + }, + { + "key": "default2", + "type": "text", + "label": "in progress" + } + ] + }] + }, + { + "type": "dict", + "collapsable": true, + "key": "publish", + "label": "Publish plugins", + "is_file": true, + "children": [{ + "type": "dict", + "collapsable": true, + "checkbox_key": "enabled", + "key": "IntegrateFtrackNote", + "label": "IntegrateFtrackNote", + "is_group": true, + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "text", + "key": "note_with_intent_template", + "label": "Note with intent template" + }, { + "type": "list", + "object_type": "text", + "key": "note_labels", + "label": "Note labels" + }] + }] + } + ] + } + ] +} diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_hiero.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_hiero.json new file mode 100644 index 0000000000..d80a6272c5 --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_hiero.json @@ -0,0 +1,43 @@ +{ + "type": "dict", + "collapsable": true, + "key": "hiero", + "label": "Hiero", + "is_file": true, + "children": [{ + "type": "dict", + "collapsable": true, + "key": "publish", + "label": "Publish plugins", + "children": [{ + "type": "dict", + "collapsable": true, + "checkbox_key": "enabled", + "key": "CollectInstanceVersion", + "label": "Collect Instance Version", + "is_group": true, + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }] + }, { + "type": "dict", + "collapsable": true, + "checkbox_key": "enabled", + "key": "ExtractReviewCutUpVideo", + "label": "Extract Review Cut Up Video", + "is_group": true, + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "list", + "object_type": "text", + "key": "tags_addition", + "label": "Tags addition" + }] + }] + }] +} diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_maya.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_maya.json new file mode 100644 index 0000000000..6ef30a349d --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_maya.json @@ -0,0 +1,28 @@ +{ + "type": "dict", + "collapsable": true, + "key": "maya", + "label": "Maya", + "is_file": true, + "children": [{ + "type": "dict", + "collapsable": true, + "key": "maya", + "label": "Maya", + "children": [ + + { + "type": "schema", + "name": "2_maya_capture" + }, + { + "type": "schema", + "name": "2_maya_plugins" + }, + { + "type": "schema", + "name": "2_maya_workfiles" + } + ] + }] +} diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_nuke.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_nuke.json new file mode 100644 index 0000000000..3151a26b45 --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_nuke.json @@ -0,0 +1,140 @@ +{ + "type": "dict", + "collapsable": true, + "key": "nuke", + "label": "Nuke", + "is_file": true, + "children": [{ + "type": "dict", + "collapsable": true, + "key": "create", + "label": "Create plugins", + "children": [{ + "type": "dict", + "collapsable": false, + "key": "CreateWriteRender", + "label": "CreateWriteRender", + "is_group": true, + "children": [{ + "type": "text", + "key": "fpath_template", + "label": "Path template" + }] + }, { + "type": "dict", + "collapsable": false, + "key": "CreateWritePrerender", + "label": "CreateWritePrerender", + "is_group": true, + "children": [{ + "type": "text", + "key": "fpath_template", + "label": "Path template" + }] + }] + }, { + "type": "dict", + "collapsable": true, + "key": "publish", + "label": "Publish plugins", + "children": [{ + "type": "dict", + "collapsable": true, + "checkbox_key": "enabled", + "key": "ExtractThumbnail", + "label": "ExtractThumbnail", + "is_group": true, + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "raw-json", + "key": "nodes", + "label": "Nodes" + }] + }, { + "type": "dict", + "collapsable": true, + "checkbox_key": "enabled", + "key": "ValidateNukeWriteKnobs", + "label": "ValidateNukeWriteKnobs", + "is_group": true, + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "raw-json", + "key": "knobs", + "label": "Knobs" + }] + }, { + "type": "dict", + "collapsable": true, + "checkbox_key": "enabled", + "key": "ExtractReviewDataLut", + "label": "ExtractReviewDataLut", + "is_group": true, + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }] + }, { + "type": "dict", + "collapsable": true, + "checkbox_key": "enabled", + "key": "ExtractReviewDataMov", + "label": "ExtractReviewDataMov", + "is_group": true, + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "boolean", + "key": "viewer_lut_raw", + "label": "Viewer LUT raw" + }] + }, { + "type": "dict", + "collapsable": true, + "key": "ExtractSlateFrame", + "label": "ExtractSlateFrame", + "is_group": true, + "children": [{ + "type": "boolean", + "key": "viewer_lut_raw", + "label": "Viewer LUT raw" + }] + }, { + "type": "dict", + "collapsable": true, + "key": "NukeSubmitDeadline", + "label": "NukeSubmitDeadline", + "is_group": true, + "children": [{ + "type": "number", + "key": "deadline_priority", + "label": "deadline_priority" + }, { + "type": "text", + "key": "deadline_pool", + "label": "deadline_pool" + }, { + "type": "text", + "key": "deadline_pool_secondary", + "label": "deadline_pool_secondary" + }, { + "type": "number", + "key": "deadline_chunk_size", + "label": "deadline_chunk_size" + }] + }] + }, { + "type": "raw-json", + "key": "workfile_build", + "label": "Workfile Build logic" + }] +} diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_resolve.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_resolve.json new file mode 100644 index 0000000000..9452911354 --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_resolve.json @@ -0,0 +1,35 @@ +{ + "type": "dict", + "collapsable": true, + "key": "resolve", + "label": "DaVinci Resolve", + "is_file": true, + "children": [{ + "type": "dict", + "collapsable": true, + "key": "create", + "label": "Creator plugins", + "children": [{ + "type": "dict", + "collapsable": true, + "key": "CreateShotClip", + "label": "Create Shot Clip", + "is_group": true, + "children": [{ + "type": "text", + "key": "clipName", + "label": "Clip name template" + }, { + "type": "text", + "key": "folder", + "label": "Folder" + }, { + "type": "number", + "key": "steps", + "label": "Steps" + }] + } + + ] + }] +} diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json b/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json new file mode 100644 index 0000000000..86570e2ac8 --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json @@ -0,0 +1,147 @@ +{ + "type": "dict", + "key": "Ftrack", + "label": "Ftrack", + "collapsable": true, + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "text", + "key": "ftrack_server", + "label": "Server" + }, + { + "type": "splitter" + }, + { + "type": "label", + "label": "Additional Ftrack paths" + }, + { + "type": "list", + "key": "ftrack_actions_path", + "label": "Action paths", + "object_type": "text" + }, + { + "type": "list", + "key": "ftrack_events_path", + "label": "Event paths", + "object_type": "text" + }, + { + "type": "splitter" + }, + { + "type": "label", + "label": "Ftrack event server advanced settings" + }, + { + "type": "text", + "key": "FTRACK_EVENTS_MONGO_DB", + "label": "Event Mongo DB" + }, + { + "type": "text", + "key": "FTRACK_EVENTS_MONGO_COL", + "label": "Events Mongo Collection" + }, + { + "type": "dict", + "key": "events", + "label": "Server Events", + "children": [{ + "type": "dict", + "key": "sync_to_avalon", + "label": "Sync to avalon", + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "list", + "key": "statuses_name_change", + "label": "Status name change", + "object_type": { + "type": "text", + "multiline": false + } + }] + }, + { + "type": "dict", + "key": "status_version_to_task", + "label": "Version to Task status mapping", + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "dict-modifiable", + "key": "statuses", + "label": "Stausesg", + "object_type": "text" + }] + }, + { + "type": "dict", + "key": "status_update", + "label": "Status Updates", + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "key": "statuses", + "type": "dict-invisible", + "children": [ + { + "key": "default", + "type": "text", + "label": "complete" + }, + { + "key": "default2", + "type": "text", + "label": "in progress" + } + ] + }] + } + ] + }, + { + "key": "intent", + "type": "dict-invisible", + "children": [{ + "type": "dict-modifiable", + "object_type": "text", + "key": "items", + "label": "Intent Key/Label" + }, + { + "key": "default", + "type": "text", + "label": "Default Intent" + } + ] + }, + { + "type": "splitter" + }, + { + "key": "environment", + "label": "Environment", + "type": "raw-json", + "env_group_key": "ftrack" + } + ] +} diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/schema_modules.json b/pype/tools/settings/settings/gui_schemas/system_schema/schema_modules.json index fa84a27ae3..31eaab2ede 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/schema_modules.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/schema_modules.json @@ -5,286 +5,184 @@ "collapsable": true, "is_file": true, "children": [{ - "type": "dict", - "key": "Avalon", - "label": "Avalon", - "collapsable": true, - "children": [{ - "type": "text", - "key": "AVALON_MONGO", - "label": "Avalon Mongo URL" - }, - { - "type": "text", - "key": "AVALON_DB_DATA", - "label": "Avalon Mongo Data Location" - }, - { - "type": "text", - "key": "AVALON_THUMBNAIL_ROOT", - "label": "Thumbnail Storage Location" - }, - { - "key": "environment", - "label": "Environment", - "type": "raw-json", - "env_group_key": "avalon" - } - ] - }, { - "type": "dict", - "key": "Ftrack", - "label": "Ftrack", - "collapsable": true, - "checkbox_key": "enabled", - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, - { - "type": "text", - "key": "ftrack_server", - "label": "Server" - }, - { - "type": "splitter" - }, - { - "type": "label", - "label": "Additional Ftrack paths" - }, - { - "type": "list", - "key": "ftrack_actions_path", - "label": "Action paths", - "object_type": "text" - }, - { - "type": "list", - "key": "ftrack_events_path", - "label": "Event paths", - "object_type": "text" - }, - { - "type": "splitter" - }, - { - "type": "label", - "label": "Ftrack event server advanced settings" - }, - { - "type": "text", - "key": "FTRACK_EVENTS_MONGO_DB", - "label": "Event Mongo DB" - }, - { - "type": "text", - "key": "FTRACK_EVENTS_MONGO_COL", - "label": "Events Mongo Collection" - }, - { - "type": "dict", - "key": "sync_to_avalon", - "label": "Sync to avalon", - "children": [{ - "type": "list", - "key": "statuses_name_change", - "label": "Status name change", - "object_type": { - "type": "text", - "multiline": false - } - }] - }, - { - "type": "dict-modifiable", - "key": "status_version_to_task", - "label": "Version to Task status mapping", - "object_type": "text" - }, - { - "type": "dict-modifiable", - "key": "status_update", - "label": "Status Updates", - "object_type": { - "type": "list", - "object_type": "text" + "type": "dict", + "key": "Avalon", + "label": "Avalon", + "collapsable": true, + "children": [{ + "type": "text", + "key": "AVALON_MONGO", + "label": "Avalon Mongo URL" + }, + { + "type": "text", + "key": "AVALON_DB_DATA", + "label": "Avalon Mongo Data Location" + }, + { + "type": "text", + "key": "AVALON_THUMBNAIL_ROOT", + "label": "Thumbnail Storage Location" + }, + { + "key": "environment", + "label": "Environment", + "type": "raw-json", + "env_group_key": "avalon" } - }, - { - "key": "intent", - "type": "dict-invisible", - "children": [{ - "type": "dict-modifiable", - "object_type": "text", - "key": "items", - "label": "Intent Key/Label" - }, - { - "key": "default", - "type": "text", - "label": "Default Intent" - } - ] - }, - { - "type": "splitter" - }, - { - "key": "environment", - "label": "Environment", - "type": "raw-json", - "env_group_key": "ftrack" - } - ] - }, { - "type": "dict", - "key": "Rest Api", - "label": "Rest Api", - "collapsable": true, - "children": [{ - "type": "number", - "key": "default_port", - "label": "Default Port", - "minimum": 1, - "maximum": 65535 - }, - { - "type": "list", - "key": "exclude_ports", - "label": "Exclude ports", - "object_type": { + ] + }, { + "type": "schema", + "name": "schema_ftrack" + }, + { + "type": "dict", + "key": "Rest Api", + "label": "Rest Api", + "collapsable": true, + "children": [{ "type": "number", + "key": "default_port", + "label": "Default Port", "minimum": 1, "maximum": 65535 + }, + { + "type": "list", + "key": "exclude_ports", + "label": "Exclude ports", + "object_type": { + "type": "number", + "minimum": 1, + "maximum": 65535 + } } - } - ] - }, { - "type": "dict", - "key": "Timers Manager", - "label": "Timers Manager", - "collapsable": true, - "checkbox_key": "enabled", - "children": [{ + ] + }, { + "type": "dict", + "key": "Timers Manager", + "label": "Timers Manager", + "collapsable": true, + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "number", + "decimal": 2, + "key": "full_time", + "label": "Max idle time" + }, { + "type": "number", + "decimal": 2, + "key": "message_time", + "label": "When dialog will show" + } + ] + }, { + "type": "dict", + "key": "Clockify", + "label": "Clockify", + "collapsable": true, + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "text", + "key": "workspace_name", + "label": "Workspace name" + } + ] + }, { + "type": "dict", + "key": "Deadline", + "label": "Deadline", + "collapsable": true, + "checkbox_key": "enabled", + "children": [{ "type": "boolean", "key": "enabled", "label": "Enabled" - }, - { - "type": "number", - "decimal": 2, - "key": "full_time", - "label": "Max idle time" }, { - "type": "number", - "decimal": 2, - "key": "message_time", - "label": "When dialog will show" - } - ] - }, { - "type": "dict", - "key": "Clockify", - "label": "Clockify", - "collapsable": true, - "checkbox_key": "enabled", - "children": [{ + "type": "text", + "key": "DEADLINE_REST_URL", + "label": "Deadline Resl URL" + }] + }, { + "type": "dict", + "key": "Muster", + "label": "Muster", + "collapsable": true, + "checkbox_key": "enabled", + "children": [{ "type": "boolean", "key": "enabled", "label": "Enabled" - }, - { + }, { "type": "text", - "key": "workspace_name", - "label": "Workspace name" - } - ] - }, { - "type": "dict", - "key": "Deadline", - "label": "Deadline", - "collapsable": true, - "checkbox_key": "enabled", - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" + "key": "MUSTER_REST_URL", + "label": "Muster Resl URL" + }, { + "type": "dict-modifiable", + "object_type": { + "type": "number", + "minimum": 0, + "maximum": 300 + }, + "is_group": true, + "key": "templates_mapping", + "label": "Templates mapping", + "is_file": true + }] }, { - "type": "text", - "key": "DEADLINE_REST_URL", - "label": "Deadline Resl URL" - }] - }, { - "type": "dict", - "key": "Muster", - "label": "Muster", - "collapsable": true, - "checkbox_key": "enabled", - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" + "type": "dict", + "key": "Logging", + "label": "Logging", + "collapsable": true, + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }] }, { - "type": "text", - "key": "MUSTER_REST_URL", - "label": "Muster Resl URL" + "type": "dict", + "key": "User setting", + "label": "User setting", + "collapsable": true, + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }] }, { - "type": "dict-modifiable", - "object_type": { - "type": "number", - "minimum": 0, - "maximum": 300 - }, - "is_group": true, - "key": "templates_mapping", - "label": "Templates mapping", - "is_file": true - }] - }, { - "type": "dict", - "key": "Logging", - "label": "Logging", - "collapsable": true, - "checkbox_key": "enabled", - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }] - }, { - "type": "dict", - "key": "User setting", - "label": "User setting", - "collapsable": true, - "checkbox_key": "enabled", - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }] - }, { - "type": "dict", - "key": "Standalone Publish", - "label": "Standalone Publish", - "collapsable": true, - "checkbox_key": "enabled", - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }] - }, { - "type": "dict", - "key": "Idle Manager", - "label": "Idle Manager", - "collapsable": true, - "checkbox_key": "enabled", - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }] - }] + "type": "dict", + "key": "Standalone Publish", + "label": "Standalone Publish", + "collapsable": true, + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }] + }, { + "type": "dict", + "key": "Idle Manager", + "label": "Idle Manager", + "collapsable": true, + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }] + } + ] } From 12de5bdb5fe1eede2d267fcdd945bef447ea39db Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 18:25:15 +0100 Subject: [PATCH 056/279] simplified condition --- pype/tools/settings/settings/widgets/item_types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 15ba817f29..4cfca93824 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2217,7 +2217,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.content_widget = content_widget self.content_layout = content_layout - if not as_widget and body_widget: + if body_widget: collapsable = input_data.get("collapsable", True) if collapsable: collapsed = input_data.get("collapsed", True) From 800efd6ead03f22b1d7d44a93236c00ff87f1c1e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 19:04:55 +0100 Subject: [PATCH 057/279] do not validate on `set_value` in strict list --- pype/tools/settings/settings/widgets/item_types.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 4cfca93824..99b2f593a9 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1897,8 +1897,6 @@ class ListStrictWidget(QtWidgets.QWidget, InputObject): return self._default_input_value def set_value(self, value): - self.validate_value(value) - if self._is_overriden: method_name = "apply_overrides" elif not self._has_studio_override: From efeb53aa23e29a1aad327e2d9e6e018f30df64d9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 19:23:03 +0100 Subject: [PATCH 058/279] fix missing object attribute --- pype/tools/settings/settings/widgets/item_types.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 99b2f593a9..be508d6617 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2186,15 +2186,14 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): elif label is None: body_widget = None - self.body_widget = body_widget self.label_widget = None else: body_widget = ExpandingWidget(input_data["label"], self) main_layout.addWidget(body_widget) - self.body_widget = body_widget self.label_widget = body_widget.label_widget + self.body_widget = body_widget if body_widget is None: content_parent_widget = self else: From f4e442cb333efb90b57cee4def50633d7da9c3b8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 22:05:58 +0100 Subject: [PATCH 059/279] removed DictInvisible --- .../settings/settings/widgets/item_types.py | 295 +----------------- 1 file changed, 1 insertion(+), 294 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index fd5364ea17..7a7b95ee3b 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2835,299 +2835,6 @@ class DictWidget(QtWidgets.QWidget, SettingObject): return self._override_values(True) -class DictInvisible(QtWidgets.QWidget, SettingObject): - # TODO is not overridable by itself - value_changed = QtCore.Signal(object) - allow_actions = False - expand_in_grid = True - valid_value_types = (dict, type(NOT_SET)) - - def __init__( - self, input_data, parent, - as_widget=False, label_widget=None, parent_widget=None - ): - if parent_widget is None: - parent_widget = parent - super(DictInvisible, self).__init__(parent_widget) - self.setObjectName("DictInvisible") - - self.initial_attributes(input_data, parent, as_widget) - - if self._is_group: - raise TypeError("DictInvisible can't be marked as group input.") - - self.setAttribute(QtCore.Qt.WA_TranslucentBackground) - - layout = QtWidgets.QGridLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(5) - - self.content_layout = layout - - self.input_fields = [] - - self.key = input_data["key"] - - for child_data in input_data.get("children", []): - self.add_children_gui(child_data) - - any_visible = False - for input_field in self.input_fields: - if not input_field.hidden_by_role: - any_visible = True - break - - if not any_visible: - self.hide() - - def add_children_gui(self, child_configuration): - item_type = child_configuration["type"] - klass = TypeToKlass.types.get(item_type) - - row = self.content_layout.rowCount() - if not getattr(klass, "is_input_type", False): - item = klass(child_configuration, self) - self.content_layout.addWidget(item, row, 0, 1, 2) - return item - - label_widget = None - if not klass.expand_in_grid: - label = child_configuration.get("label") - if label is not None: - label_widget = GridLabelWidget(label, self) - self.content_layout.addWidget(label_widget, row, 0, 1, 1) - - item = klass(child_configuration, self, label_widget=label_widget) - item.value_changed.connect(self._on_value_change) - - if label_widget: - if item.hidden_by_role: - label_widget.hide() - label_widget.input_field = item - self.content_layout.addWidget(item, row, 1, 1, 1) - else: - self.content_layout.addWidget(item, row, 0, 1, 2) - - self.input_fields.append(item) - return item - - def update_style(self, *args, **kwargs): - return - - @property - def child_has_studio_override(self): - for input_field in self.input_fields: - if ( - input_field.has_studio_override - or input_field.child_has_studio_override - ): - return True - return False - - @property - def child_modified(self): - for input_field in self.input_fields: - if input_field.child_modified: - return True - return False - - @property - def child_overriden(self): - for input_field in self.input_fields: - if input_field.is_overriden or input_field.child_overriden: - return True - return False - - @property - def child_invalid(self): - for input_field in self.input_fields: - if input_field.child_invalid: - return True - return False - - def get_invalid(self): - output = [] - for input_field in self.input_fields: - output.extend(input_field.get_invalid()) - return output - - def item_value(self): - output = {} - for input_field in self.input_fields: - # TODO maybe merge instead of update should be used - # NOTE merge is custom function which merges 2 dicts - output.update(input_field.config_value()) - return output - - def _on_value_change(self, item=None): - if self.ignore_value_changes: - return - - if self.is_group and not self.any_parent_as_widget: - if self.is_overidable: - self._is_overriden = True - else: - self._has_studio_override = True - self.hierarchical_style_update() - - self.value_changed.emit(self) - - def hierarchical_style_update(self): - for input_field in self.input_fields: - input_field.hierarchical_style_update() - self.update_style() - - def remove_overrides(self): - self._is_overriden = False - self._is_modified = False - for input_field in self.input_fields: - input_field.remove_overrides() - - def reset_to_pype_default(self): - for input_field in self.input_fields: - input_field.reset_to_pype_default() - self._has_studio_override = False - - def set_studio_default(self): - for input_field in self.input_fields: - input_field.set_studio_default() - - if self.is_group: - self._has_studio_override = True - - def discard_changes(self): - self._is_modified = False - self._is_overriden = self._was_overriden - self._has_studio_override = self._had_studio_override - - for input_field in self.input_fields: - input_field.discard_changes() - - self._is_modified = self.child_modified - if not self.is_overidable and self.as_widget: - if self.has_studio_override: - self._is_modified = self.studio_value != self.item_value() - else: - self._is_modified = self.default_value != self.item_value() - - self._state = None - self._is_overriden = self._was_overriden - - def set_as_overriden(self): - if self.is_overriden: - return - - if self.is_group: - self._is_overriden = True - return - - for item in self.input_fields: - item.set_as_overriden() - - def update_default_values(self, parent_values): - value = NOT_SET - if self.as_widget: - value = parent_values - elif parent_values is not NOT_SET: - value = parent_values.get(self.key, NOT_SET) - - try: - self.validate_value(value) - except InvalidValueType as exc: - value = NOT_SET - self.log.warning(exc.msg) - - for item in self.input_fields: - item.update_default_values(value) - - def update_studio_values(self, parent_values): - value = NOT_SET - if parent_values is not NOT_SET: - value = parent_values.get(self.key, NOT_SET) - - try: - self.validate_value(value) - except InvalidValueType as exc: - value = NOT_SET - self.log.warning(exc.msg) - - for item in self.input_fields: - item.update_studio_values(value) - - def apply_overrides(self, parent_values): - # Make sure this is set to False - self._state = None - self._child_state = None - - metadata = {} - groups = tuple() - override_values = NOT_SET - if parent_values is not NOT_SET: - metadata = parent_values.get(METADATA_KEY) or metadata - groups = metadata.get("groups") or groups - override_values = parent_values.get(self.key, override_values) - - self._is_overriden = self.key in groups - - try: - self.validate_value(override_values) - except InvalidValueType as exc: - override_values = NOT_SET - self.log.warning(exc.msg) - - for item in self.input_fields: - item.apply_overrides(override_values) - - if not self._is_overriden: - self._is_overriden = ( - self.is_group - and self.is_overidable - and self.child_overriden - ) - self._was_overriden = bool(self._is_overriden) - - def _override_values(self, project_overrides): - values = {} - groups = [] - for input_field in self.input_fields: - if project_overrides: - value, is_group = input_field.overrides() - else: - value, is_group = input_field.studio_overrides() - if value is NOT_SET: - continue - - if METADATA_KEY in value and METADATA_KEY in values: - new_metadata = value.pop(METADATA_KEY) - values[METADATA_KEY] = self.merge_metadata( - values[METADATA_KEY], new_metadata - ) - - values.update(value) - if is_group: - groups.extend(value.keys()) - - if groups: - if METADATA_KEY not in values: - values[METADATA_KEY] = {} - values[METADATA_KEY]["groups"] = groups - return {self.key: values}, self.is_group - - def studio_overrides(self): - if ( - not (self.as_widget or self.any_parent_as_widget) - and not self.has_studio_override - and not self.child_has_studio_override - ): - return NOT_SET, False - return self._override_values(False) - - def overrides(self): - if not self.is_overriden and not self.child_overriden: - return NOT_SET, False - return self._override_values(True) - - class PathWidget(QtWidgets.QWidget, SettingObject): value_changed = QtCore.Signal(object) platforms = ("windows", "darwin", "linux") @@ -3768,7 +3475,7 @@ TypeToKlass.types["dict-modifiable"] = ModifiableDict # DEPRECATED - remove when removed from schemas TypeToKlass.types["dict-item"] = DictWidget TypeToKlass.types["dict"] = DictWidget -TypeToKlass.types["dict-invisible"] = DictInvisible +TypeToKlass.types["dict-invisible"] = DictWidget TypeToKlass.types["path-widget"] = PathWidget TypeToKlass.types["form"] = DictFormWidget From 5443e0e0f906ffd35964212a35c4db0db244b80c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 22:06:59 +0100 Subject: [PATCH 060/279] modified DictWidget to be able not have label part --- .../settings/settings/widgets/item_types.py | 153 ++++++++++-------- 1 file changed, 86 insertions(+), 67 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 7a7b95ee3b..aef1a0ae19 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2180,24 +2180,22 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): main_layout.setContentsMargins(0, 0, 0, 0) main_layout.setSpacing(0) + label = input_data.get("label") + if as_widget: body_widget = None self.label_widget = label_widget + + elif label is None: + body_widget = None + self.label_widget = None else: body_widget = ExpandingWidget(input_data["label"], self) main_layout.addWidget(body_widget) - self.body_widget = body_widget self.label_widget = body_widget.label_widget - collapsable = input_data.get("collapsable", True) - if collapsable: - collapsed = input_data.get("collapsed", True) - if not collapsed: - body_widget.toggle_content() - - else: - body_widget.hide_toolbox(hide_content=False) + self.body_widget = body_widget if body_widget is None: content_parent_widget = self @@ -2219,6 +2217,16 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.content_widget = content_widget self.content_layout = content_layout + if body_widget: + collapsable = input_data.get("collapsable", True) + if collapsable: + collapsed = input_data.get("collapsed", True) + if not collapsed: + body_widget.toggle_content() + + else: + body_widget.hide_toolbox(hide_content=False) + self.setAttribute(QtCore.Qt.WA_TranslucentBackground) self.add_row(is_empty=True) @@ -2419,12 +2427,16 @@ class DictWidget(QtWidgets.QWidget, SettingObject): self.checkbox_widget = None self.checkbox_key = input_data.get("checkbox_key") - self.label_widget = label_widget + if not self.as_widget: + self.key = input_data["key"] - if self.as_widget: - self._ui_as_widget(input_data) + if not self.as_widget and input_data.get("label") is None: + self._ui_item_without_label() else: - self._ui_as_item(input_data) + self._ui_item_or_as_widget(input_data, label_widget) + + for child_data in input_data.get("children", []): + self.add_children_gui(child_data) any_visible = False for input_field in self.input_fields: @@ -2435,68 +2447,70 @@ class DictWidget(QtWidgets.QWidget, SettingObject): if not any_visible: self.hide() - def _ui_as_item(self, input_data): - self.key = input_data["key"] - if input_data.get("highlight_content", False): - content_state = "hightlighted" - bottom_margin = 5 + def _ui_item_without_label(self): + self.setObjectName("DictInvisible") + + self.label_widget = None + self.body_widget = None + self.content_layout = QtWidgets.QGridLayout(self) + self.content_layout.setContentsMargins(0, 0, 0, 0) + self.content_layout.setSpacing(5) + + def _ui_item_or_as_widget(self, input_data, label_widget): + content_widget = QtWidgets.QWidget(self) + + if self.as_widget: + content_widget.setObjectName("DictAsWidgetBody") + show_borders = str( + int(input_data.get("show_borders", True)) + ) + content_widget.setProperty("show_borders", show_borders) + content_layout_margins = (5, 5, 5, 5) + main_layout_spacing = 5 + body_widget = None + else: - content_state = "" - bottom_margin = 0 + content_widget.setObjectName("ContentWidget") + if input_data.get("highlight_content", False): + content_state = "hightlighted" + bottom_margin = 5 + else: + content_state = "" + bottom_margin = 0 + content_widget.setProperty("content_state", content_state) + content_layout_margins = (CHILD_OFFSET, 5, 0, bottom_margin) + main_layout_spacing = 0 + + body_widget = ExpandingWidget(input_data["label"], self) + label_widget = body_widget.label_widget + body_widget.set_content_widget(content_widget) + + content_layout = QtWidgets.QGridLayout(content_widget) + content_layout.setContentsMargins(*content_layout_margins) main_layout = QtWidgets.QHBoxLayout(self) main_layout.setContentsMargins(0, 0, 0, 0) - main_layout.setSpacing(0) - - body_widget = ExpandingWidget(input_data["label"], self) - - main_layout.addWidget(body_widget) - - content_widget = QtWidgets.QWidget(body_widget) - content_widget.setObjectName("ContentWidget") - content_widget.setProperty("content_state", content_state) - content_layout = QtWidgets.QGridLayout(content_widget) - content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, bottom_margin) - - body_widget.set_content_widget(content_widget) - - self.body_widget = body_widget - self.content_widget = content_widget - self.content_layout = content_layout - - self.label_widget = body_widget.label_widget - - for child_data in input_data.get("children", []): - self.add_children_gui(child_data) - - collapsable = input_data.get("collapsable", True) - if len(self.input_fields) == 1 and self.checkbox_widget: - body_widget.hide_toolbox(hide_content=True) - - elif collapsable: - collapsed = input_data.get("collapsed", True) - if not collapsed: - body_widget.toggle_content() + main_layout.setSpacing(main_layout_spacing) + if not body_widget: + main_layout.addWidget(content_widget) else: - body_widget.hide_toolbox(hide_content=False) + main_layout.addWidget(body_widget) - def _ui_as_widget(self, input_data): - body = QtWidgets.QWidget(self) - body.setObjectName("DictAsWidgetBody") - show_borders = str(int(input_data.get("show_borders", True))) - body.setProperty("show_borders", show_borders) - - content_layout = QtWidgets.QGridLayout(body) - content_layout.setContentsMargins(5, 5, 5, 5) + self.label_widget = label_widget + self.body_widget = body_widget self.content_layout = content_layout - layout = QtWidgets.QHBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(5) - layout.addWidget(body) + if body_widget: + collapsable = input_data.get("collapsable", True) + if len(self.input_fields) == 1 and self.checkbox_widget: + body_widget.hide_toolbox(hide_content=True) - for child_configuration in input_data["children"]: - self.add_children_gui(child_configuration) + elif collapsable: + collapsed = input_data.get("collapsed", True) + if not collapsed: + body_widget.toggle_content() + else: + body_widget.hide_toolbox(hide_content=False) def add_children_gui(self, child_configuration): item_type = child_configuration["type"] @@ -2516,6 +2530,11 @@ class DictWidget(QtWidgets.QWidget, SettingObject): "SCHEMA BUG: Dictionary item has set as checkbox" " item invalid type \"{}\". Expected \"boolean\"." ).format(child_configuration["type"])) + elif self.body_widget is None: + self.log.warning(( + "SCHEMA BUG: Dictionary item has set checkbox" + " item but item does not have label." + ).format(child_configuration["type"])) else: return self._add_checkbox_child(child_configuration) @@ -2706,7 +2725,7 @@ class DictWidget(QtWidgets.QWidget, SettingObject): def update_style(self, is_overriden=None): # TODO add style update when used as widget - if self.as_widget: + if not self.body_widget: return child_has_studio_override = self.child_has_studio_override From 595bd9022482e9d977ccb65140298644244e9097 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Wed, 25 Nov 2020 22:08:16 +0100 Subject: [PATCH 061/279] rename project host settings --- .../projects_schema/0_project_gui_schema.json | 26 +++- ...ns_gui_schema.json => schema_plugins.json} | 0 .../schema_project_celaction.json | 0 .../{schemas => }/schema_project_ftrack.json | 144 +++++++++++------- .../{schemas => }/schema_project_hiero.json | 0 .../{schemas => }/schema_project_maya.json | 6 +- .../{schemas => }/schema_project_nuke.json | 0 .../{schemas => }/schema_project_resolve.json | 0 .../schema_maya_capture.json} | 0 .../schema_maya_plugins.json} | 0 .../schema_maya_workfiles.json} | 0 .../module_settings/schema_ftrack.json | 47 +++--- 12 files changed, 132 insertions(+), 91 deletions(-) rename pype/tools/settings/settings/gui_schemas/projects_schema/{1_plugins_gui_schema.json => schema_plugins.json} (100%) rename pype/tools/settings/settings/gui_schemas/projects_schema/{schemas => }/schema_project_celaction.json (100%) rename pype/tools/settings/settings/gui_schemas/projects_schema/{schemas => }/schema_project_ftrack.json (54%) rename pype/tools/settings/settings/gui_schemas/projects_schema/{schemas => }/schema_project_hiero.json (100%) rename pype/tools/settings/settings/gui_schemas/projects_schema/{schemas => }/schema_project_maya.json (76%) rename pype/tools/settings/settings/gui_schemas/projects_schema/{schemas => }/schema_project_nuke.json (100%) rename pype/tools/settings/settings/gui_schemas/projects_schema/{schemas => }/schema_project_resolve.json (100%) rename pype/tools/settings/settings/gui_schemas/projects_schema/{2_maya_capture.json => schemas/schema_maya_capture.json} (100%) rename pype/tools/settings/settings/gui_schemas/projects_schema/{2_maya_plugins.json => schemas/schema_maya_plugins.json} (100%) rename pype/tools/settings/settings/gui_schemas/projects_schema/{2_maya_workfiles.json => schemas/schema_maya_workfiles.json} (100%) diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json b/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json index 5b19a1159a..7409b45533 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json @@ -23,7 +23,31 @@ "children": [ { "type": "schema", - "name": "1_plugins_gui_schema" + "name": "schema_project_ftrack" + }, + { + "type": "schema", + "name": "schema_project_maya" + }, + { + "type": "schema", + "name": "schema_project_nuke" + }, + { + "type": "schema", + "name": "schema_project_hiero" + }, + { + "type": "schema", + "name": "schema_project_celaction" + }, + { + "type": "schema", + "name": "schema_project_resolve" + }, + { + "type": "schema", + "name": "schema_plugins" } ] } diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/1_plugins_gui_schema.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_plugins.json similarity index 100% rename from pype/tools/settings/settings/gui_schemas/projects_schema/1_plugins_gui_schema.json rename to pype/tools/settings/settings/gui_schemas/projects_schema/schema_plugins.json diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_celaction.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_celaction.json similarity index 100% rename from pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_celaction.json rename to pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_celaction.json diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_ftrack.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json similarity index 54% rename from pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_ftrack.json rename to pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json index 1d6b4cbf5b..767321f835 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_ftrack.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json @@ -32,41 +32,7 @@ "type": "dict", "key": "events", "label": "Server Events", - "children": [{ - "type": "dict", - "key": "sync_to_avalon", - "label": "Sync to avalon", - "checkbox_key": "enabled", - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "list", - "key": "statuses_name_change", - "label": "Status name change", - "object_type": { - "type": "text", - "multiline": false - } - }] - }, - { - "type": "dict", - "key": "status_version_to_task", - "label": "Version to Task status mapping", - "checkbox_key": "enabled", - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "dict-modifiable", - "key": "statuses", - "label": "Stausesg", - "object_type": "text" - }] - }, + "children": [ { "type": "dict", "key": "status_update", @@ -96,34 +62,94 @@ }, { "type": "dict", - "collapsable": true, - "key": "publish", - "label": "Publish plugins", - "is_file": true, + "key": "status_task_to_parent", + "label": "Sync status from Task to Parent", + "checkbox_key": "enabled", "children": [{ - "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "IntegrateFtrackNote", - "label": "IntegrateFtrackNote", - "is_group": true, - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "text", - "key": "note_with_intent_template", - "label": "Note with intent template" - }, { - "type": "list", - "object_type": "text", - "key": "note_labels", - "label": "Note labels" - }] + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }] + }, + { + "type": "dict", + "key": "status_task_to_version", + "label": "Sync status from Task to Version", + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }] + }, + { + "type": "dict", + "key": "status_version_to_task", + "label": "Sync status from Version to Task", + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "dict-modifiable", + "key": "statuses", + "label": "statuses", + "object_type": "text" + }] + }, + { + "type": "dict", + "key": "first_version_status", + "label": "Set status on first created version", + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }] + }, + { + "type": "dict", + "key": "next_task_update", + "label": "Update status on next task", + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" }] } ] + }, + { + "type": "dict", + "collapsable": true, + "key": "publish", + "label": "Publish plugins", + "is_file": true, + "children": [{ + "type": "dict", + "collapsable": true, + "checkbox_key": "enabled", + "key": "IntegrateFtrackNote", + "label": "IntegrateFtrackNote", + "is_group": true, + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "text", + "key": "note_with_intent_template", + "label": "Note with intent template" + }, { + "type": "list", + "object_type": "text", + "key": "note_labels", + "label": "Note labels" + }] + }] } ] } diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_hiero.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_hiero.json similarity index 100% rename from pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_hiero.json rename to pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_hiero.json diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_maya.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_maya.json similarity index 76% rename from pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_maya.json rename to pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_maya.json index 6ef30a349d..38c7ff81a1 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_maya.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_maya.json @@ -13,15 +13,15 @@ { "type": "schema", - "name": "2_maya_capture" + "name": "schema_maya_capture" }, { "type": "schema", - "name": "2_maya_plugins" + "name": "schema_maya_plugins" }, { "type": "schema", - "name": "2_maya_workfiles" + "name": "schema_maya_workfiles" } ] }] diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_nuke.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_nuke.json similarity index 100% rename from pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_nuke.json rename to pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_nuke.json diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_resolve.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_resolve.json similarity index 100% rename from pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_project_resolve.json rename to pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_resolve.json diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_capture.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_capture.json similarity index 100% rename from pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_capture.json rename to pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_capture.json diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_plugins.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_plugins.json similarity index 100% rename from pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_plugins.json rename to pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_plugins.json diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_workfiles.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_workfiles.json similarity index 100% rename from pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_workfiles.json rename to pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_workfiles.json diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json b/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json index 86570e2ac8..4ce23c75f7 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json @@ -54,7 +54,8 @@ "type": "dict", "key": "events", "label": "Server Events", - "children": [{ + "children": [ + { "type": "dict", "key": "sync_to_avalon", "label": "Sync to avalon", @@ -73,47 +74,37 @@ } }] }, - { + { "type": "dict", - "key": "status_version_to_task", - "label": "Version to Task status mapping", + "key": "push_frame_values_to_task", + "label": "Sync Hierarchical and Entity Attributes", "checkbox_key": "enabled", "children": [{ "type": "boolean", "key": "enabled", "label": "Enabled" - }, { - "type": "dict-modifiable", - "key": "statuses", - "label": "Stausesg", - "object_type": "text" }] }, - { + { "type": "dict", - "key": "status_update", - "label": "Status Updates", + "key": "thumbnail_updates", + "label": "Update Hierarchy thumbnails", + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }] + }, + { + "type": "dict", + "key": "user_assignment", + "label": "Update Hierarchy thumbnails", "checkbox_key": "enabled", "children": [{ "type": "boolean", "key": "enabled", "label": "Enabled" - }, - { - "key": "statuses", - "type": "dict-invisible", - "children": [ - { - "key": "default", - "type": "text", - "label": "complete" - }, - { - "key": "default2", - "type": "text", - "label": "in progress" - } - ] }] } ] From f2f10d91d10b469bdd37791f578a8c06883543eb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 22:50:20 +0100 Subject: [PATCH 062/279] added `_is_group` check --- pype/tools/settings/settings/widgets/item_types.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index aef1a0ae19..b235e38ab5 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2448,6 +2448,11 @@ class DictWidget(QtWidgets.QWidget, SettingObject): self.hide() def _ui_item_without_label(self): + if self._is_group: + raise TypeError( + "Dictionary without label can't be marked as group input." + ) + self.setObjectName("DictInvisible") self.label_widget = None From ed47e11dedf196d9a74cb5d9bc337686648cd8b0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 22:50:32 +0100 Subject: [PATCH 063/279] updated readme and examples --- pype/tools/settings/settings/README.md | 55 +++++++++---------- .../system_schema/example_schema.json | 4 +- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/pype/tools/settings/settings/README.md b/pype/tools/settings/settings/README.md index 4f4e9d305a..046f903f90 100644 --- a/pype/tools/settings/settings/README.md +++ b/pype/tools/settings/settings/README.md @@ -116,43 +116,29 @@ ## Basic Dictionary inputs - these inputs wraps another inputs into {key: value} relation -### dict-invisible -- this input gives ability to wrap another inputs but keep them in same widget without visible divider - - this is for example used as first input widget -- has required keys `"key"` and `"children"` - - "children" says what children inputs are underneath - - "key" is key under which will be stored value from it's children -- output is dictionary `{the "key": children values}` -- can't have `"is_group"` key set to True as it breaks visual override showing -``` -{ - "type": "dict-invisible", - "key": "global", - "children": [ - ...ITEMS... - ] -} -``` - ## dict - this is another dictionary input wrapping more inputs but visually makes them different - item may be used as widget (in `list` or `dict-modifiable`) - in that case the only key modifier is `children` which is list of it's keys - USAGE: e.g. List of dictionaries where each dictionary have same structure. -- item options if is not used as widget - - required keys are `"key"` under which will be stored and `"label"` which will be shown in GUI - - this input can be expandable - - that can be set with key `"expandable"` as `True`/`False` (Default: `True`) - - with key `"expanded"` as `True`/`False` can be set that is expanded when GUI is opened (Default: `False`) - - it is possible to add darker background with `"highlight_content"` (Default: `False`) - - darker background has limits of maximum applies after 3-4 nested highlighted items there is not difference in the color +- item may be with or without `"label"` if is not used as widget + - required keys are `"key"` under which will be stored + - without label it is just wrap item holding `"key"` + - can't have `"is_group"` key set to True as it breaks visual override showing + - if `"label"` is entetered there which will be shown in GUI + - item with label can be collapsable + - that can be set with key `"collapsable"` as `True`/`False` (Default: `True`) + - with key `"collapsed"` as `True`/`False` can be set that is collapsed when GUI is opened (Default: `False`) + - it is possible to add darker background with `"highlight_content"` (Default: `False`) + - darker background has limits of maximum applies after 3-4 nested highlighted items there is not difference in the color + - output is dictionary `{the "key": children values}` ``` # Example { "key": "applications", "type": "dict", "label": "Applications", - "expandable": true, + "collapsable": true, "highlight_content": true, "is_group": true, "is_file": true, @@ -161,13 +147,22 @@ ] } +# Without label +{ + "type": "dict", + "key": "global", + "children": [ + ...ITEMS... + ] +} + # When used as widget { "type": "list", "key": "profiles", "label": "Profiles", "object_type": { - "type": "dict-item", + "type": "dict", "children": [ { "key": "families", @@ -318,9 +313,9 @@ - there are 2 possible ways how to set the type: 1.) dictionary with item modifiers (`number` input has `minimum`, `maximum` and `decimals`) in that case item type must be set as value of `"type"` (example below) 2.) item type name as string without modifiers (e.g. `text`) -- this input can be expandable - - that can be set with key `"expandable"` as `True`/`False` (Default: `True`) - - with key `"expanded"` as `True`/`False` can be set that is expanded when GUI is opened (Default: `False`) +- this input can be collapsable + - that can be set with key `"collapsable"` as `True`/`False` (Default: `True`) + - with key `"collapsed"` as `True`/`False` can be set that is collapsed when GUI is opened (Default: `False`) 1.) with item modifiers ``` diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/example_schema.json b/pype/tools/settings/settings/gui_schemas/system_schema/example_schema.json index 7612e54116..a3e7f52776 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/example_schema.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/example_schema.json @@ -40,7 +40,7 @@ ] }, { "key": "dict_wrapper", - "type": "dict-invisible", + "type": "dict", "children": [ { "type": "enum", @@ -248,7 +248,7 @@ "key": "dict_item", "label": "DictItem in List", "object_type": { - "type": "dict-item", + "type": "dict", "children": [ { "key": "families", From 6b13ab2f1d9c8c1a9ecfe9d6bc40058910817f24 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 22:55:49 +0100 Subject: [PATCH 064/279] moved few lines --- pype/tools/settings/settings/widgets/item_types.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index b235e38ab5..769ddca5ad 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -3498,8 +3498,9 @@ TypeToKlass.types["enum"] = EnumeratorWidget TypeToKlass.types["dict-modifiable"] = ModifiableDict # DEPRECATED - remove when removed from schemas TypeToKlass.types["dict-item"] = DictWidget -TypeToKlass.types["dict"] = DictWidget TypeToKlass.types["dict-invisible"] = DictWidget +# --------------------------------------------- +TypeToKlass.types["dict"] = DictWidget TypeToKlass.types["path-widget"] = PathWidget TypeToKlass.types["form"] = DictFormWidget From 663887ec2ff05e7520a743a62fe5fd8cf8349787 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 23:04:07 +0100 Subject: [PATCH 065/279] used dict instead of dict-invisible in schemas --- .../system_schema/host_settings/schema_blender.json | 2 +- .../system_schema/host_settings/schema_celaction.json | 2 +- .../gui_schemas/system_schema/host_settings/schema_djv.json | 2 +- .../system_schema/host_settings/schema_fusion.json | 2 +- .../system_schema/host_settings/schema_harmony.json | 2 +- .../system_schema/host_settings/schema_houdini.json | 2 +- .../gui_schemas/system_schema/host_settings/schema_maya.json | 2 +- .../system_schema/host_settings/schema_mayabatch.json | 2 +- .../system_schema/host_settings/schema_photoshop.json | 2 +- .../system_schema/host_settings/schema_resolve.json | 2 +- .../gui_schemas/system_schema/host_settings/schema_shell.json | 2 +- .../system_schema/host_settings/schema_unreal.json | 2 +- .../system_schema/host_settings/template_nuke.json | 2 +- .../settings/gui_schemas/system_schema/schema_main.json | 4 ++-- .../settings/gui_schemas/system_schema/schema_modules.json | 2 +- .../settings/gui_schemas/system_schema/schema_tools.json | 2 +- 16 files changed, 17 insertions(+), 17 deletions(-) diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_blender.json b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_blender.json index 28adf347b1..1cdd6825bc 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_blender.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_blender.json @@ -20,7 +20,7 @@ "env_group_key": "blender" }, { - "type": "dict-invisible", + "type": "dict", "key": "variants", "children": [{ "type": "schema_template", diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_celaction.json b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_celaction.json index ac872267d8..8a78aaf187 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_celaction.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_celaction.json @@ -20,7 +20,7 @@ "env_group_key": "celaction" }, { - "type": "dict-invisible", + "type": "dict", "key": "variants", "children": [{ "type": "schema_template", diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_djv.json b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_djv.json index 987bb382db..4ebb97d5bd 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_djv.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_djv.json @@ -20,7 +20,7 @@ "env_group_key": "djvview" }, { - "type": "dict-invisible", + "type": "dict", "key": "variants", "children": [{ "type": "schema_template", diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_fusion.json b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_fusion.json index b2ce01b7db..38fdc2d067 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_fusion.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_fusion.json @@ -20,7 +20,7 @@ "env_group_key": "fusion" }, { - "type": "dict-invisible", + "type": "dict", "key": "variants", "children": [{ "type": "schema_template", diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_harmony.json b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_harmony.json index 80bc9864f0..d7b9e61bda 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_harmony.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_harmony.json @@ -20,7 +20,7 @@ "env_group_key": "harmony" }, { - "type": "dict-invisible", + "type": "dict", "key": "variants", "children": [{ "type": "schema_template", diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_houdini.json b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_houdini.json index ace2a3106c..be319198ba 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_houdini.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_houdini.json @@ -20,7 +20,7 @@ "env_group_key": "houdini" }, { - "type": "dict-invisible", + "type": "dict", "key": "variants", "children": [{ "type": "schema_template", diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_maya.json b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_maya.json index eb055863b8..4ecf2362fa 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_maya.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_maya.json @@ -21,7 +21,7 @@ "env_group_key": "maya" }, { - "type": "dict-invisible", + "type": "dict", "key": "variants", "children": [{ "type": "schema_template", diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_mayabatch.json b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_mayabatch.json index 27d2ca68cd..43d281991a 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_mayabatch.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_mayabatch.json @@ -21,7 +21,7 @@ "env_group_key": "mayabatch" }, { - "type": "dict-invisible", + "type": "dict", "key": "variants", "children": [{ "type": "schema_template", diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_photoshop.json b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_photoshop.json index f86f6ff055..755cad12c4 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_photoshop.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_photoshop.json @@ -20,7 +20,7 @@ "env_group_key": "photoshop" }, { - "type": "dict-invisible", + "type": "dict", "key": "variants", "children": [{ "type": "schema_template", diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_resolve.json b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_resolve.json index e6d0a6a84d..4871d0ebb8 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_resolve.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_resolve.json @@ -20,7 +20,7 @@ "env_group_key": "resolve" }, { - "type": "dict-invisible", + "type": "dict", "key": "variants", "children": [{ "type": "schema_template", diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_shell.json b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_shell.json index bbc86c53ee..389d480a45 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_shell.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_shell.json @@ -16,7 +16,7 @@ "env_group_key": "shell" }, { - "type": "dict-invisible", + "type": "dict", "key": "variants", "children": [{ "type": "schema_template", diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_unreal.json b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_unreal.json index 6c2778f470..859d73614b 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_unreal.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_unreal.json @@ -20,7 +20,7 @@ "env_group_key": "unreal" }, { - "type": "dict-invisible", + "type": "dict", "key": "variants", "children": [{ "type": "schema_template", diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/template_nuke.json b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/template_nuke.json index e8a8fc3799..d335891b70 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/template_nuke.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/template_nuke.json @@ -20,7 +20,7 @@ "env_group_key": "{nuke_type}" }, { - "type": "dict-invisible", + "type": "dict", "key": "variants", "children": [{ "type": "schema_template", diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/schema_main.json b/pype/tools/settings/settings/gui_schemas/system_schema/schema_main.json index 8e8798149c..039d00401c 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/schema_main.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/schema_main.json @@ -1,9 +1,9 @@ { "key": "system", - "type": "dict-invisible", + "type": "dict", "children": [ { - "type": "dict-invisible", + "type": "dict", "key": "global", "children": [{ "type": "schema", diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/schema_modules.json b/pype/tools/settings/settings/gui_schemas/system_schema/schema_modules.json index fa84a27ae3..9d6aa7ccb5 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/schema_modules.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/schema_modules.json @@ -114,7 +114,7 @@ }, { "key": "intent", - "type": "dict-invisible", + "type": "dict", "children": [{ "type": "dict-modifiable", "object_type": "text", diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/schema_tools.json b/pype/tools/settings/settings/gui_schemas/system_schema/schema_tools.json index 97fbd5c390..c8f4829a09 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/schema_tools.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/schema_tools.json @@ -18,7 +18,7 @@ "name": "schema_yeti" }, { - "type": "dict-invisible", + "type": "dict", "key": "other", "children": [ { From adb1b8457963dfd3581fb9ad6afccd05778af416 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 23:29:02 +0100 Subject: [PATCH 066/279] storing env metadata in raw json moved back to config_value --- .../settings/settings/widgets/item_types.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index be508d6617..ee15ddda6b 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1328,18 +1328,17 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): output = {} for key, value in value.items(): output[key.upper()] = value - - if self.is_environ: - output[METADATA_KEY] = { - "environments": { - self.env_group_key: list(output.keys()) - } - } - return output def config_value(self): - return {self.key: self.item_value()} + value = self.item_value() + if self.is_environ: + value[METADATA_KEY] = { + "environments": { + self.env_group_key: list(value.keys()) + } + } + return {self.key: value} class ListItem(QtWidgets.QWidget, SettingObject): From 7d7561f2a608b58436f14e32fdb146814eef140b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 23:29:33 +0100 Subject: [PATCH 067/279] ModifiableDict adds env metadata to output in config_value if is marked to store env groups keys --- pype/tools/settings/settings/widgets/item_types.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index ee15ddda6b..e59db34367 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2334,6 +2334,18 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): output.update(item.config_value()) return output + def config_value(self): + output = self.item_value() + if self.value_is_env_group: + for key, value in tuple(output.items()): + value[METADATA_KEY] = { + "environments": { + key: list(value.keys()) + } + } + output[key] = value + return {self.key: output} + def add_row(self, row=None, key=None, value=None, is_empty=False): # Create new item item_widget = ModifiableDictItem( From 724245cf2f224b9d12589fd7ad76020467f62a6a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 25 Nov 2020 23:38:08 +0100 Subject: [PATCH 068/279] removed label from what was set as dict-invisible and changed to dict --- .../projects_schema/0_project_gui_schema.json | 4 +-- .../projects_schema/1_plugins_gui_schema.json | 6 ++-- .../projects_schema/2_maya_capture.json | 32 +++++-------------- 3 files changed, 12 insertions(+), 30 deletions(-) diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json b/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json index cf95bf4c45..bc9ec2dc9d 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json @@ -1,6 +1,6 @@ { "key": "project", - "type": "dict-invisible", + "type": "dict", "children": [ { "type": "anatomy", @@ -17,7 +17,7 @@ } ] }, { - "type": "dict-invisible", + "type": "dict", "key": "project_settings", "children": [ { diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/1_plugins_gui_schema.json b/pype/tools/settings/settings/gui_schemas/projects_schema/1_plugins_gui_schema.json index 87912cfdc0..16ca661604 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/1_plugins_gui_schema.json @@ -121,7 +121,7 @@ "key": "enabled", "label": "Enabled" }, { - "type": "dict-invisible", + "type": "dict", "key": "ffmpeg_args", "children": [{ "type": "list", @@ -328,10 +328,8 @@ }] }] }, { - "type": "dict-invisible", - "collapsable": true, + "type": "dict", "key": "maya", - "label": "Maya", "children": [{ "type": "dict", "collapsable": true, diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_capture.json b/pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_capture.json index 836ad90404..ae3e67a7fc 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_capture.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_capture.json @@ -6,10 +6,8 @@ "is_file": true, "children": [ { - "type": "dict-invisible", + "type": "dict", "key": "Codec", - "label": "Codec", - "collapsable": false, "children": [ { "type": "label", @@ -37,10 +35,8 @@ } ] }, { - "type": "dict-invisible", + "type": "dict", "key": "Display Options", - "label": "Display Options", - "collapsable": false, "children": [ { "type": "label", @@ -132,10 +128,8 @@ "type": "splitter" } , { - "type": "dict-invisible", - "collapsable": true, + "type": "dict", "key": "Generic", - "label": "Generic", "children": [ { "type": "label", @@ -152,10 +146,8 @@ } ] },{ - "type": "dict-invisible", - "collapsable": true, + "type": "dict", "key": "IO", - "label": "IO", "children": [ { "type": "label", @@ -185,10 +177,8 @@ } ] },{ - "type": "dict-invisible", - "collapsable": true, + "type": "dict", "key": "PanZoom", - "label": "Pan Zoom", "children": [ { "type": "boolean", @@ -200,10 +190,8 @@ { "type": "splitter" },{ - "type": "dict-invisible", - "collapsable": true, + "type": "dict", "key": "Renderer", - "label": "Renderer", "children": [ { @@ -217,10 +205,8 @@ } ] },{ - "type": "dict-invisible", - "collapsable": true, + "type": "dict", "key": "Resolution", - "label": "Resolution", "children": [ { @@ -262,10 +248,8 @@ "type": "splitter" }, { - "type": "dict-invisible", - "collapsable": true, + "type": "dict", "key": "Time Range", - "label": "Time Range", "children": [ { "type": "label", From 647053273e83a03814401bc9633dd573681f54f5 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 26 Nov 2020 00:01:34 +0100 Subject: [PATCH 069/279] convert ftrack settings --- .../defaults/project_settings/Ftrack.json | 73 +++++++++++++++++++ .../schema_project_ftrack.json | 68 ++++++++++++----- 2 files changed, 122 insertions(+), 19 deletions(-) create mode 100644 pype/settings/defaults/project_settings/Ftrack.json diff --git a/pype/settings/defaults/project_settings/Ftrack.json b/pype/settings/defaults/project_settings/Ftrack.json new file mode 100644 index 0000000000..7c9bb8ce0e --- /dev/null +++ b/pype/settings/defaults/project_settings/Ftrack.json @@ -0,0 +1,73 @@ +{ + "ftrack_actions_path": [], + "ftrack_events_path": [], + "events": { + "status_update": { + "enabled": true, + "mapping": { + "In Progress": [ + "__any__" + ], + "Ready": [ + "Not Ready" + ], + "__ignore__": [ + "in prgoress", + "omitted", + "on hold" + ] + } + }, + "status_task_to_parent": { + "enabled": true, + "parent_status_match_all_task_statuses": { + "Completed": [ + "Approved", + "Omitted" + ] + }, + "parent_status_by_task_status": { + "In Progress": [ + "in progress", + "change requested", + "retake", + "pending review" + ] + } + }, + "status_task_to_version": { + "enabled": true, + "mapping": { + "Approved": [ + "Complete" + ] + } + }, + "status_version_to_task": { + "enabled": true, + "mapping": { + "Complete": [ + "Approved", + "Complete" + ] + } + }, + "first_version_status": { + "enabled": true, + "status": "" + }, + "next_task_update": { + "enabled": true, + "mapping": { + "Ready": "Not Ready" + } + } + }, + "publish": { + "IntegrateFtrackNote": { + "enabled": true, + "note_with_intent_template": "", + "note_labels": [] + } + } +} \ No newline at end of file diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json index 767321f835..a7c835081a 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json @@ -36,7 +36,7 @@ { "type": "dict", "key": "status_update", - "label": "Status Updates", + "label": "Update status on task action", "checkbox_key": "enabled", "children": [{ "type": "boolean", @@ -44,20 +44,12 @@ "label": "Enabled" }, { - "key": "statuses", - "type": "dict-invisible", - "children": [ - { - "key": "default", - "type": "text", - "label": "complete" - }, - { - "key": "default2", - "type": "text", - "label": "in progress" - } - ] + "key": "mapping", + "type": "dict-modifiable", + "object_type": { + "type": "list", + "object_type": "text" + } }] }, { @@ -69,6 +61,24 @@ "type": "boolean", "key": "enabled", "label": "Enabled" + }, + { + "key": "parent_status_match_all_task_statuses", + "type": "dict-modifiable", + "label": "Change parent if all tasks match", + "object_type": { + "type": "list", + "object_type": "text" + } + }, + { + "key": "parent_status_by_task_status", + "type": "dict-modifiable", + "label": "Change parent status if a single task matches", + "object_type": { + "type": "list", + "object_type": "text" + } }] }, { @@ -80,6 +90,13 @@ "type": "boolean", "key": "enabled", "label": "Enabled" + }, { + "type": "dict-modifiable", + "key": "mapping", + "object_type": { + "type": "list", + "object_type": "text" + } }] }, { @@ -93,9 +110,11 @@ "label": "Enabled" }, { "type": "dict-modifiable", - "key": "statuses", - "label": "statuses", - "object_type": "text" + "key": "mapping", + "object_type": { + "type": "list", + "object_type": "text" + } }] }, { @@ -107,7 +126,12 @@ "type": "boolean", "key": "enabled", "label": "Enabled" - }] + },{ + "type": "text", + "key": "status", + "label": "Status" + } + ] }, { "type": "dict", @@ -118,6 +142,12 @@ "type": "boolean", "key": "enabled", "label": "Enabled" + },{ + "type": "dict-modifiable", + "key": "mapping", + "object_type": { + "type": "text" + } }] } ] From 112e1e6aca76713896121957abf9f7da0c52c7b0 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 26 Nov 2020 00:01:55 +0100 Subject: [PATCH 070/279] separate hosts in project settings --- .../defaults/project_settings/celaction.json | 13 ++ .../defaults/project_settings/hiero.json | 11 + .../defaults/project_settings/maya.json | 220 ++++++++++++++++++ .../defaults/project_settings/nuke.json | 62 +++++ .../plugins/maya/workfile_build.json | 17 +- .../defaults/project_settings/resolve.json | 9 + .../system_settings/global/modules.json | 29 ++- 7 files changed, 340 insertions(+), 21 deletions(-) create mode 100644 pype/settings/defaults/project_settings/celaction.json create mode 100644 pype/settings/defaults/project_settings/hiero.json create mode 100644 pype/settings/defaults/project_settings/maya.json create mode 100644 pype/settings/defaults/project_settings/nuke.json create mode 100644 pype/settings/defaults/project_settings/resolve.json diff --git a/pype/settings/defaults/project_settings/celaction.json b/pype/settings/defaults/project_settings/celaction.json new file mode 100644 index 0000000000..10165e92de --- /dev/null +++ b/pype/settings/defaults/project_settings/celaction.json @@ -0,0 +1,13 @@ +{ + "publish": { + "ExtractCelactionDeadline": { + "enabled": true, + "deadline_department": "", + "deadline_priority": 0, + "deadline_pool": "", + "deadline_pool_secondary": "", + "deadline_group": "", + "deadline_chunk_size": 0 + } + } +} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/hiero.json b/pype/settings/defaults/project_settings/hiero.json new file mode 100644 index 0000000000..8d31f2d56d --- /dev/null +++ b/pype/settings/defaults/project_settings/hiero.json @@ -0,0 +1,11 @@ +{ + "publish": { + "CollectInstanceVersion": { + "enabled": true + }, + "ExtractReviewCutUpVideo": { + "enabled": true, + "tags_addition": [] + } + } +} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/maya.json b/pype/settings/defaults/project_settings/maya.json new file mode 100644 index 0000000000..d9ec13b3ed --- /dev/null +++ b/pype/settings/defaults/project_settings/maya.json @@ -0,0 +1,220 @@ +{ + "maya_capture": { + "Codec": { + "compression": "jpg", + "format": "image", + "quality": 95 + }, + "Display Options": { + "background": [ + 0.7, + 0.7, + 0.7 + ], + "backgroundBottom": [ + 0.7, + 0.7, + 0.7 + ], + "backgroundTop": [ + 0.7, + 0.7, + 0.7 + ], + "override_display": true + }, + "Generic": { + "isolate_view": true, + "off_screen": true + }, + "IO": { + "name": "", + "open_finished": true, + "raw_frame_numbers": true, + "recent_playblasts": [], + "save_file": true + }, + "PanZoom": { + "pan_zoom": true + }, + "Renderer": { + "rendererName": "vp2Renderer" + }, + "Resolution": { + "width": 1080, + "height": 1920, + "percent": 1.0, + "mode": "Custom" + }, + "Time Range": { + "start_frame": 0, + "end_frame": 0, + "frame": "", + "time": "Time Slider" + }, + "Viewport Options": { + "cameras": false, + "clipGhosts": false, + "controlVertices": false, + "deformers": false, + "dimensions": false, + "displayLights": 0, + "dynamicConstraints": false, + "dynamics": false, + "fluids": false, + "follicles": false, + "gpuCacheDisplayFilter": false, + "greasePencils": false, + "grid": false, + "hairSystems": true, + "handles": false, + "high_quality": true, + "hud": false, + "hulls": false, + "ikHandles": false, + "imagePlane": true, + "joints": false, + "lights": false, + "locators": false, + "manipulators": false, + "motionTrails": false, + "nCloths": false, + "nParticles": false, + "nRigids": false, + "nurbsCurves": false, + "nurbsSurfaces": false, + "override_viewport_options": true, + "particleInstancers": false, + "pivots": false, + "planes": false, + "pluginShapes": false, + "polymeshes": true, + "shadows": true, + "strokes": false, + "subdivSurfaces": false, + "textures": false, + "twoSidedLighting": true + }, + "Camera Options": { + "displayGateMask": false, + "displayResolution": false, + "displayFilmGate": false, + "displayFieldChart": false, + "displaySafeAction": false, + "displaySafeTitle": false, + "displayFilmPivot": false, + "displayFilmOrigin": false, + "overscan": 1.0 + } + }, + "publish": { + "ValidateModelName": { + "enabled": true, + "material_file": { + "windows": "", + "darwin": "", + "linux": "" + }, + "regex": "" + }, + "ValidateAssemblyName": { + "enabled": true + }, + "ValidateShaderName": { + "enabled": true, + "regex": "" + }, + "ValidateMeshHasOverlappingUVs": { + "enabled": true + } + }, + "workfile_build": { + "profiles": [ + { + "tasks": [ + "Lighting" + ], + "current_context": [ + { + "subset_name_filters": [ + "\".+[Mm]ain\"" + ], + "families": [ + "model" + ], + "repre_names": [ + "abc", + "ma" + ], + "loaders": [ + "ReferenceLoader" + ] + }, + { + "subset_name_filters": [], + "families": [ + "animation", + "pointcache" + ], + "repre_names": [ + "abc" + ], + "loaders": [ + "ReferenceLoader" + ] + }, + { + "subset_name_filters": [], + "families": [ + "rendersetup" + ], + "repre_names": [ + "json" + ], + "loaders": [ + "RenderSetupLoader" + ] + }, + { + "subset_name_filters": [], + "families": [ + "camera" + ], + "repre_names": [ + "abc" + ], + "loaders": [ + "ReferenceLoader" + ] + } + ], + "linked_assets": [ + { + "subset_name_filters": [], + "families": [ + "sedress" + ], + "repre_names": [ + "ma" + ], + "loaders": [ + "ReferenceLoader" + ] + }, + { + "subset_name_filters": [], + "families": [ + "ArnoldStandin" + ], + "repre_names": [ + "ass" + ], + "loaders": [ + "assLoader" + ] + } + ] + } + ] + } +} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/nuke.json b/pype/settings/defaults/project_settings/nuke.json new file mode 100644 index 0000000000..98b4f55aa4 --- /dev/null +++ b/pype/settings/defaults/project_settings/nuke.json @@ -0,0 +1,62 @@ +{ + "create": { + "CreateWriteRender": { + "fpath_template": "" + }, + "CreateWritePrerender": { + "fpath_template": "" + } + }, + "publish": { + "ExtractThumbnail": { + "enabled": true, + "nodes": {} + }, + "ValidateNukeWriteKnobs": { + "enabled": true, + "knobs": {} + }, + "ExtractReviewDataLut": { + "enabled": true + }, + "ExtractReviewDataMov": { + "enabled": true, + "viewer_lut_raw": true + }, + "ExtractSlateFrame": { + "viewer_lut_raw": true + }, + "NukeSubmitDeadline": { + "deadline_priority": 0, + "deadline_pool": "", + "deadline_pool_secondary": "", + "deadline_chunk_size": 0 + } + }, + "workfile_build": { + "profiles": [ + { + "tasks": [ + "compositing" + ], + "current_context": [ + { + "subset_name_filters": [], + "families": [ + "render", + "plate" + ], + "repre_names": [ + "exr", + "dpx" + ], + "loaders": [ + "LoadSequence" + ] + } + ], + "linked_assets": [] + } + ] + } +} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/plugins/maya/workfile_build.json b/pype/settings/defaults/project_settings/plugins/maya/workfile_build.json index 443bc2cb2c..1aad307895 100644 --- a/pype/settings/defaults/project_settings/plugins/maya/workfile_build.json +++ b/pype/settings/defaults/project_settings/plugins/maya/workfile_build.json @@ -1,10 +1,8 @@ -[ - { +[{ "tasks": [ "lighting" ], - "current_context": [ - { + "current_context": [{ "subset_name_filters": [ ".+[Mm]ain" ], @@ -54,8 +52,7 @@ ] } ], - "linked_assets": [ - { + "linked_assets": [{ "families": [ "setdress" ], @@ -83,8 +80,7 @@ "tasks": [ "animation" ], - "current_context": [ - { + "current_context": [{ "families": [ "camera" ], @@ -108,8 +104,7 @@ ] } ], - "linked_assets": [ - { + "linked_assets": [{ "families": [ "setdress" ], @@ -133,4 +128,4 @@ } ] } -] \ No newline at end of file +] diff --git a/pype/settings/defaults/project_settings/resolve.json b/pype/settings/defaults/project_settings/resolve.json new file mode 100644 index 0000000000..646eb3a70b --- /dev/null +++ b/pype/settings/defaults/project_settings/resolve.json @@ -0,0 +1,9 @@ +{ + "create": { + "CreateShotClip": { + "clipName": "", + "folder": "", + "steps": 0 + } + } +} \ No newline at end of file diff --git a/pype/settings/defaults/system_settings/global/modules.json b/pype/settings/defaults/system_settings/global/modules.json index 6c7a45cca3..386e37b246 100644 --- a/pype/settings/defaults/system_settings/global/modules.json +++ b/pype/settings/defaults/system_settings/global/modules.json @@ -31,19 +31,28 @@ "sync_to_avalon": { "enabled": true, "statuses_name_change": [ - "not ready" + "not ready", + "ready" ] + }, + "push_frame_values_to_task": { + "enabled": true, + "interest_entity_types": [ + "shot" + ], + "interest_attributess": [ + "frameStart", + "frameEnd" + ] + }, + "thumbnail_updates": { + "enabled": true, + "levels": 2 + }, + "user_assignment": { + "enabled": true } }, - "status_version_to_task": {}, - "status_update": { - "Ready": [ - "Not Ready" - ], - "In Progress": [ - "_any_" - ] - }, "intent": { "items": { "-": "-", From 6259a27659b3a0b10c12ecaffa1fd735468f960a Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 26 Nov 2020 00:02:05 +0100 Subject: [PATCH 071/279] fill more host schemas --- .../projects_schema/schema_project_maya.json | 29 +++---- .../projects_schema/schema_project_nuke.json | 8 +- .../schemas/schema_maya_capture.json | 2 +- .../schemas/schema_maya_workfiles.json | 6 -- .../schemas/schema_workfile_build.json | 82 +++++++++++++++++++ .../module_settings/schema_ftrack.json | 76 ++++++++++++----- 6 files changed, 154 insertions(+), 49 deletions(-) delete mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_workfiles.json create mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_workfile_build.json diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_maya.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_maya.json index 38c7ff81a1..0d8db078ea 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_maya.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_maya.json @@ -5,24 +5,15 @@ "label": "Maya", "is_file": true, "children": [{ - "type": "dict", - "collapsable": true, - "key": "maya", - "label": "Maya", - "children": [ - - { - "type": "schema", - "name": "schema_maya_capture" - }, - { - "type": "schema", - "name": "schema_maya_plugins" - }, - { - "type": "schema", - "name": "schema_maya_workfiles" - } - ] + "type": "schema", + "name": "schema_maya_capture" + }, + { + "type": "schema", + "name": "schema_maya_plugins" + }, + { + "type": "schema", + "name": "schema_workfile_build" }] } diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_nuke.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_nuke.json index 3151a26b45..f928ec6039 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_nuke.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_nuke.json @@ -132,9 +132,9 @@ "label": "deadline_chunk_size" }] }] - }, { - "type": "raw-json", - "key": "workfile_build", - "label": "Workfile Build logic" + }, + { + "type": "schema", + "name": "schema_workfile_build" }] } diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_capture.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_capture.json index 836ad90404..67cd4db496 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_capture.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_capture.json @@ -2,7 +2,7 @@ "type": "dict", "collapsable": true, "key": "maya_capture", - "label": "Maya Capture settings", + "label": "Maya Playblast settings", "is_file": true, "children": [ { diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_workfiles.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_workfiles.json deleted file mode 100644 index bae4d32abd..0000000000 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_workfiles.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "raw-json", - "key": "workfile_build", - "label": "Workfile Build logic", - "is_file": true -} diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_workfile_build.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_workfile_build.json new file mode 100644 index 0000000000..d8d5b0b09b --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_workfile_build.json @@ -0,0 +1,82 @@ +{ + "type": "dict", + "collapsable": true, + "key": "workfile_build", + "label": "Workfile Build Settings", + "is_group": true, + "children": [{ + "type": "list", + "key": "profiles", + "label": "Profiles", + "object_type": { + "type": "dict", + "children": [{ + "key": "tasks", + "label": "Tasks", + "type": "list", + "object_type": "text" + }, { + "type": "splitter" + }, { + "key": "current_context", + "label": "Current Context", + "type": "list", + "highlight_content": true, + "object_type": { + "type": "dict", + "children": [{ + "key": "subset_name_filters", + "label": "Subset name Filters", + "type": "list", + "object_type": "text" + }, { + "key": "families", + "label": "Families", + "type": "list", + "object_type": "text" + },{ + "key": "repre_names", + "label": "Repre Names", + "type": "list", + "object_type": "text" + },{ + "key": "loaders", + "label": "Loaders", + "type": "list", + "object_type": "text" + }] + } + }, + { + "key": "linked_assets", + "label": "Linked Assets", + "type": "list", + "highlight_content": true, + "object_type": { + "type": "dict", + "children": [{ + "key": "subset_name_filters", + "label": "Subset name Filters", + "type": "list", + "object_type": "text" + }, { + "key": "families", + "label": "Families", + "type": "list", + "object_type": "text" + },{ + "key": "repre_names", + "label": "Repre Names", + "type": "list", + "object_type": "text" + },{ + "key": "loaders", + "label": "Loaders", + "type": "list", + "object_type": "text" + }] + } + }] + } + }] +} diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json b/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json index 4ce23c75f7..9a0d36ad06 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json @@ -54,27 +54,32 @@ "type": "dict", "key": "events", "label": "Server Events", - "children": [ - { + "children": [{ "type": "dict", "key": "sync_to_avalon", "label": "Sync to avalon", "checkbox_key": "enabled", "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "list", - "key": "statuses_name_change", - "label": "Status name change", - "object_type": { - "type": "text", - "multiline": false + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "label", + "label": "Allow name and hierarchy change only if following statuses are on all children tasks" + }, + { + "type": "list", + "key": "statuses_name_change", + "label": "Statuses", + "object_type": { + "type": "text", + "multiline": false + } } - }] + ] }, - { + { "type": "dict", "key": "push_frame_values_to_task", "label": "Sync Hierarchical and Entity Attributes", @@ -83,9 +88,25 @@ "type": "boolean", "key": "enabled", "label": "Enabled" + }, { + "type": "list", + "key": "interest_entity_types", + "label": "Entity types of interest", + "object_type": { + "type": "text", + "multiline": false + } + }, { + "type": "list", + "key": "interest_attributess", + "label": "Attributes to sync", + "object_type": { + "type": "text", + "multiline": false + } }] }, - { + { "type": "dict", "key": "thumbnail_updates", "label": "Update Hierarchy thumbnails", @@ -94,12 +115,19 @@ "type": "boolean", "key": "enabled", "label": "Enabled" + },{ + "type": "label", + "label": "Push thumbnail from version, up through multiple hierarchy levels." + },{ + "type": "number", + "key": "levels", + "label": "Levels" }] }, - { + { "type": "dict", "key": "user_assignment", - "label": "Update Hierarchy thumbnails", + "label": "Run script on user assignments", "checkbox_key": "enabled", "children": [{ "type": "boolean", @@ -109,14 +137,24 @@ } ] }, + { + "type": "splitter" + }, { "key": "intent", "type": "dict-invisible", "children": [{ + "type": "label", + "label": "Intent" + }, + { "type": "dict-modifiable", "object_type": "text", - "key": "items", - "label": "Intent Key/Label" + "key": "items" + }, + { + "type": "label", + "label": " " }, { "key": "default", From 8945a5b70f8091e89e50d9017a006a10dafeaf9b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 26 Nov 2020 10:35:47 +0100 Subject: [PATCH 072/279] loader change `fname` on update so it should work as expected now --- pype/plugins/tvpaint/load/load_reference_image.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pype/plugins/tvpaint/load/load_reference_image.py b/pype/plugins/tvpaint/load/load_reference_image.py index 0fa4cefc51..b3cefee4c3 100644 --- a/pype/plugins/tvpaint/load/load_reference_image.py +++ b/pype/plugins/tvpaint/load/load_reference_image.py @@ -162,6 +162,9 @@ class LoadImage(pipeline.Loader): """ # Create new containers first context = get_representation_context(representation) + # Change `fname` to new representation + self.fname = self.filepath_from_context(context) + name = container["name"] namespace = container["namespace"] new_container = self.load(context, name, namespace, {}) From 0cda87bd6351f16eea1c6e6e431f8b24738f1ec5 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 26 Nov 2020 13:34:09 +0100 Subject: [PATCH 073/279] feat(imageio): wip schema --- .../schema_anatomy_imageio.json | 274 +++++++++++++++++- 1 file changed, 273 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_anatomy_imageio.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_anatomy_imageio.json index 3fdbd3f7f9..d1a286b883 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_anatomy_imageio.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_anatomy_imageio.json @@ -1,8 +1,280 @@ { "type": "dict", "key": "imageio", - "label": "< ENTER LABEL HERE >", + "label": "Color Management (Image i/o)", "is_file": true, "children": [ + { + "key": "hosts", + "type": "dict", + "label": "Hosts", + "collapsed": false, + "collapsable": true, + "children": [ + { + "key": "hiero", + "type": "dict", + "label": "Hiero", + "children": [ + { + "key": "workfile", + "type": "dict", + "label": "Workfile", + "collapsable": false, + "children": [ + { + "type": "form", + "children": [ + { + "type": "enum", + "key": "ocioConfigName", + "label": "OpenColorIO Config", + "enum_items": [ + {"nuke-default": "nuke-default"}, + {"aces_1.0.3": "aces_1.0.3"}, + {"aces_1.1": "aces_1.1"}, + {"custom": "custom"} + ] + }, { + "type": "path-widget", + "key": "ocioconfigpath", + "label": "Custom OCIO path", + "multiplatform": true, + "multipath": true + }, { + "type": "text", + "key": "workingSpace", + "label": "Working Space" + }, { + "type": "text", + "key": "sixteenBitLut", + "label": "16 Bit Files" + }, { + "type": "text", + "key": "eightBitLut", + "label": "8 Bit Files" + }, { + "type": "text", + "key": "floatLut", + "label": "Floating Point Files" + }, { + "type": "text", + "key": "logLut", + "label": "Log Files" + }, { + "type": "text", + "key": "viewerLut", + "label": "Viewer" + }, { + "type": "text", + "key": "thumbnailLut", + "label": "Thumbnails" + } + ] + } + ] + }, { + "key": "regexInputs", + "type": "dict", + "label": "Colorspace on Inputs by regex detection", + "collapsable": false, + "children": [ + { + "type": "list", + "key": "inputs", + "label": "", + "object_type": { + "type": "dict", + "children": [ + { + "type": "text", + "key": "regex", + "label": "Regex" + }, { + "type": "text", + "key": "colorspace", + "label": "Colorspace" + } + ] + } + } + ] + } + ] + }, { + "key": "nuke", + "type": "dict", + "label": "Nuke", + "children": [ + { + "key": "workfile", + "type": "dict", + "label": "Workfile", + "collapsable": false, + "is_group": true, + "children": [ + { + "type": "form", + "children": [ + { + "type": "enum", + "key": "colorManagement", + "label": "color management", + "enum_items": [ + {"Nuke": "Nuke"}, + {"OCIO": "OCIO"} + ] + }, { + "type": "enum", + "key": "OCIO_config", + "label": "OpenColorIO Config", + "enum_items": [ + {"nuke-default": "nuke-default"}, + {"spi-vfx": "spi-vfx"}, + {"spi-anim": "spi-anim"}, + {"aces_1.0.3": "aces_0.1.1"}, + {"aces_1.0.3": "aces_0.7.1"}, + {"aces_1.0.3": "aces_1.0.1"}, + {"aces_1.0.3": "aces_1.0.3"}, + {"aces_1.1": "aces_1.1"}, + {"custom": "custom"} + ] + }, { + "type": "path-widget", + "key": "customOCIOConfigPath", + "label": "Custom OCIO config path", + "multiplatform": true, + "multipath": true + }, { + "type": "text", + "key": "workingSpaceLUT", + "label": "Working Space" + }, { + "type": "text", + "key": "monitorLut", + "label": "monitor" + }, { + "type": "text", + "key": "int8Lut", + "label": "8-bit files" + }, { + "type": "text", + "key": "int16Lut", + "label": "16-bit files" + }, { + "type": "text", + "key": "logLut", + "label": "log files" + }, { + "type": "text", + "key": "floatLut", + "label": "float files" + } + ] + } + ] + }, { + "key": "nodes", + "type": "dict", + "label": "Nodes", + "collapsable": false, + "is_group": true, + "children": [ + { + "key": "CreateWriteRender", + "label": "CreateWriteRender", + "type": "dict", + "children": [ + { + "type": "text", + "key": "nukeNodeClass", + "label": "Nuke Node Class" + }, { + "type": "splitter" + }, + { + "key": "knobs", + "label": "Knobs", + "type": "list", + "object_type": { + "type": "dict-item", + "children": [ + { + "type": "text", + "key": "name", + "label": "Name" + }, { + "type": "text", + "key": "value", + "label": "Value" + } + ] + } + } + ] + }, { + "type": "list", + "key": "custom-items", + "label": "Custom Nodes", + "object_type": { + "type": "dict", + "children": [ + { + "key": "nodeCreateFamily", + "label": "Creator Family", + "type": "text" + }, { + "type": "text", + "key": "nodeClass", + "label": "Node Class" + }, { + "type": "splitter" + }, + { + "type": "dict-modifiable", + "key": "nodeKnobs", + "label": "Node Knobs", + "highlight_content": true, + "object_type": { + "type": "text", + "key": "nodeKnobValue" + } + } + ] + } + } + ] + }, { + "key": "regexInputs", + "type": "dict", + "label": "Colorspace on Inputs by regex detection", + "collapsable": false, + "children": [ + { + "type": "list", + "key": "inputs", + "label": "", + "object_type": { + "type": "dict", + "children": [ + { + "type": "text", + "key": "regex", + "label": "Regex" + }, { + "type": "text", + "key": "colorspace", + "label": "Colorspace" + } + ] + } + } + ] + } + ] + } + + ] + } ] } From 637605327a365a38d703fe462959e5c2212b0c5e Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 26 Nov 2020 13:43:02 +0100 Subject: [PATCH 074/279] tons of config converted to settings --- .../defaults/project_settings/celaction.json | 4 +- .../ftrack/ftrack_config.json | 16 - .../ftrack/plugins/server.json | 1 - .../project_settings/ftrack/plugins/user.json | 5 - .../defaults/project_settings/global.json | 114 ++++++ .../defaults/project_settings/hiero.json | 12 +- .../defaults/project_settings/maya.json | 93 ++++- .../project_settings/maya/capture.json | 108 ------ .../muster/templates_mapping.json | 19 - .../defaults/project_settings/nuke.json | 46 ++- .../plugins/celaction/publish.json | 11 - .../project_settings/plugins/config.json | 1 - .../plugins/ftrack/publish.json | 7 - .../plugins/global/create.json | 1 - .../plugins/global/filter.json | 1 - .../project_settings/plugins/global/load.json | 1 - .../plugins/global/publish.json | 97 ----- .../project_settings/plugins/maya/create.json | 1 - .../project_settings/plugins/maya/filter.json | 9 - .../project_settings/plugins/maya/load.json | 18 - .../plugins/maya/maya/maya_capture.json | 108 ------ .../plugins/maya/maya/publish.json | 21 -- .../plugins/maya/maya/workfile_build.json | 1 - .../plugins/maya/publish.json | 17 - .../plugins/maya/workfile_build.json | 131 ------- .../project_settings/plugins/nuke/create.json | 8 - .../project_settings/plugins/nuke/load.json | 1 - .../plugins/nuke/publish.json | 53 --- .../plugins/nuke/workfile_build.json | 23 -- .../plugins/nukestudio/filter.json | 10 - .../plugins/nukestudio/publish.json | 9 - .../plugins/resolve/create.json | 7 - .../plugins/standalonepublisher/publish.json | 10 - .../project_settings/plugins/test/create.json | 8 - .../plugins/test/publish.json | 10 - .../defaults/project_settings/resolve.json | 6 +- .../project_settings/standalonepublisher.json | 114 ++++++ .../standalonepublisher/families.json | 90 ----- .../projects_schema/0_project_gui_schema.json | 6 +- .../projects_schema/schema_plugins.json | 243 +------------ .../schema_project_global.json | 343 ++++++++++++++++++ .../projects_schema/schema_project_hiero.json | 5 + .../projects_schema/schema_project_maya.json | 11 +- .../projects_schema/schema_project_nuke.json | 5 + .../schema_project_standalonepublisher.json | 159 ++++++++ .../schemas/schema_maya_load.json | 142 ++++++++ .../schemas/schema_maya_plugins.json | 90 ----- .../schemas/schema_maya_publish.json | 188 ++++++++++ .../schemas/template_color.json | 28 ++ .../schemas/template_creatorfamily.json | 43 +++ 50 files changed, 1302 insertions(+), 1153 deletions(-) delete mode 100644 pype/settings/defaults/project_settings/ftrack/ftrack_config.json delete mode 100644 pype/settings/defaults/project_settings/ftrack/plugins/server.json delete mode 100644 pype/settings/defaults/project_settings/ftrack/plugins/user.json create mode 100644 pype/settings/defaults/project_settings/global.json delete mode 100644 pype/settings/defaults/project_settings/maya/capture.json delete mode 100644 pype/settings/defaults/project_settings/muster/templates_mapping.json delete mode 100644 pype/settings/defaults/project_settings/plugins/celaction/publish.json delete mode 100644 pype/settings/defaults/project_settings/plugins/config.json delete mode 100644 pype/settings/defaults/project_settings/plugins/ftrack/publish.json delete mode 100644 pype/settings/defaults/project_settings/plugins/global/create.json delete mode 100644 pype/settings/defaults/project_settings/plugins/global/filter.json delete mode 100644 pype/settings/defaults/project_settings/plugins/global/load.json delete mode 100644 pype/settings/defaults/project_settings/plugins/global/publish.json delete mode 100644 pype/settings/defaults/project_settings/plugins/maya/create.json delete mode 100644 pype/settings/defaults/project_settings/plugins/maya/filter.json delete mode 100644 pype/settings/defaults/project_settings/plugins/maya/load.json delete mode 100644 pype/settings/defaults/project_settings/plugins/maya/maya/maya_capture.json delete mode 100644 pype/settings/defaults/project_settings/plugins/maya/maya/publish.json delete mode 100644 pype/settings/defaults/project_settings/plugins/maya/maya/workfile_build.json delete mode 100644 pype/settings/defaults/project_settings/plugins/maya/publish.json delete mode 100644 pype/settings/defaults/project_settings/plugins/maya/workfile_build.json delete mode 100644 pype/settings/defaults/project_settings/plugins/nuke/create.json delete mode 100644 pype/settings/defaults/project_settings/plugins/nuke/load.json delete mode 100644 pype/settings/defaults/project_settings/plugins/nuke/publish.json delete mode 100644 pype/settings/defaults/project_settings/plugins/nuke/workfile_build.json delete mode 100644 pype/settings/defaults/project_settings/plugins/nukestudio/filter.json delete mode 100644 pype/settings/defaults/project_settings/plugins/nukestudio/publish.json delete mode 100644 pype/settings/defaults/project_settings/plugins/resolve/create.json delete mode 100644 pype/settings/defaults/project_settings/plugins/standalonepublisher/publish.json delete mode 100644 pype/settings/defaults/project_settings/plugins/test/create.json delete mode 100644 pype/settings/defaults/project_settings/plugins/test/publish.json create mode 100644 pype/settings/defaults/project_settings/standalonepublisher.json delete mode 100644 pype/settings/defaults/project_settings/standalonepublisher/families.json create mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_global.json create mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_standalonepublisher.json create mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_load.json delete mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_plugins.json create mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_publish.json create mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/schemas/template_color.json create mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/schemas/template_creatorfamily.json diff --git a/pype/settings/defaults/project_settings/celaction.json b/pype/settings/defaults/project_settings/celaction.json index 10165e92de..a4a321fb27 100644 --- a/pype/settings/defaults/project_settings/celaction.json +++ b/pype/settings/defaults/project_settings/celaction.json @@ -3,11 +3,11 @@ "ExtractCelactionDeadline": { "enabled": true, "deadline_department": "", - "deadline_priority": 0, + "deadline_priority": 50, "deadline_pool": "", "deadline_pool_secondary": "", "deadline_group": "", - "deadline_chunk_size": 0 + "deadline_chunk_size": 10 } } } \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/ftrack/ftrack_config.json b/pype/settings/defaults/project_settings/ftrack/ftrack_config.json deleted file mode 100644 index 1ef3a9d69f..0000000000 --- a/pype/settings/defaults/project_settings/ftrack/ftrack_config.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "sync_to_avalon": { - "statuses_name_change": ["not ready", "ready"] - }, - - "status_update": { - "_ignore_": ["in progress", "ommited", "on hold"], - "Ready": ["not ready"], - "In Progress" : ["_any_"] - }, - "status_version_to_task": { - "__description__": "Status `from` (key) must be lowered!", - "in progress": "in progress", - "approved": "approved" - } -} diff --git a/pype/settings/defaults/project_settings/ftrack/plugins/server.json b/pype/settings/defaults/project_settings/ftrack/plugins/server.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/pype/settings/defaults/project_settings/ftrack/plugins/server.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/pype/settings/defaults/project_settings/ftrack/plugins/user.json b/pype/settings/defaults/project_settings/ftrack/plugins/user.json deleted file mode 100644 index 1ba8e9b511..0000000000 --- a/pype/settings/defaults/project_settings/ftrack/plugins/user.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "TestAction": { - "ignore_me": true - } -} diff --git a/pype/settings/defaults/project_settings/global.json b/pype/settings/defaults/project_settings/global.json new file mode 100644 index 0000000000..b68f6d87bd --- /dev/null +++ b/pype/settings/defaults/project_settings/global.json @@ -0,0 +1,114 @@ +{ + "publish": { + "IntegrateMasterVersion": { + "enabled": true + }, + "ExtractJpegEXR": { + "enabled": true, + "ffmpeg_args": { + "input": [], + "output": [] + } + }, + "ExtractReview": { + "enabled": true, + "profiles": [ + { + "families": [], + "hosts": [], + "outputs": { + "h264": { + "ext": "mp4", + "tags": [ + "burnin", + "ftrackreview" + ], + "ffmpeg_args": { + "video_filters": [], + "audio_filters": [], + "input": [ + "gamma 2.2" + ], + "output": [ + "pix_fmt yuv420p", + "crf 18", + "intra" + ] + }, + "filter": { + "families": [ + "render", + "review", + "ftrack" + ] + } + } + } + } + ] + }, + "ExtractBurnin": { + "enabled": true, + "options": { + "font_size": 42, + "opacity": 1, + "bg_opacity": 0, + "x_offset": 5, + "y_offset": 5, + "bg_padding": 5 + }, + "fields": {}, + "profiles": [ + { + "burnins": { + "burnin": { + "TOP_LEFT": "{yy}-{mm}-{dd}", + "TOP_RIGHT": "{anatomy[version]}", + "TOP_CENTERED": "", + "BOTTOM_RIGHT": "{frame_start}-{current_frame}-{frame_end}", + "BOTTOM_CENTERED": "{asset}", + "BOTTOM_LEFT": "{username}" + } + } + } + ] + }, + "IntegrateAssetNew": { + "template_name_profiles": { + "template_name_profiles": { + "publish": { + "families": [], + "tasks": [] + }, + "render": { + "families": [ + "review", + "render", + "prerender" + ] + } + } + } + }, + "ProcessSubmittedJobOnFarm": { + "enabled": true, + "deadline_department": "", + "deadline_pool": "", + "deadline_group": "", + "deadline_chunk_size": "", + "deadline_priority": "", + "aov_filter": { + "maya": [ + ".+(?:\\.|_)([Bb]eauty)(?:\\.|_).*" + ], + "nuke": [], + "aftereffects": [ + ".*" + ], + "celaction": [ + ".*" + ] + } + } + } +} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/hiero.json b/pype/settings/defaults/project_settings/hiero.json index 8d31f2d56d..e7e6350c29 100644 --- a/pype/settings/defaults/project_settings/hiero.json +++ b/pype/settings/defaults/project_settings/hiero.json @@ -1,11 +1,21 @@ { "publish": { "CollectInstanceVersion": { - "enabled": true + "enabled": false }, "ExtractReviewCutUpVideo": { "enabled": true, "tags_addition": [] } + }, + "filter": { + "strict": { + "ValidateVersion": true, + "VersionUpWorkfile": true + }, + "benevolent": { + "ValidateVersion": false, + "VersionUpWorkfile": false + } } } \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/maya.json b/pype/settings/defaults/project_settings/maya.json index d9ec13b3ed..f8315dc129 100644 --- a/pype/settings/defaults/project_settings/maya.json +++ b/pype/settings/defaults/project_settings/maya.json @@ -108,6 +108,13 @@ } }, "publish": { + "CollectMayaRender": { + "sync_workfile_version": true + }, + "ValidateCameraAttributes": { + "enabled": true, + "optional": true + }, "ValidateModelName": { "enabled": true, "material_file": { @@ -126,6 +133,89 @@ }, "ValidateMeshHasOverlappingUVs": { "enabled": true + }, + "ExtractCameraAlembic": { + "enabled": true, + "optional": true, + "bake_attributes": [] + }, + "MayaSubmitDeadline": { + "enabled": true, + "tile_assembler_plugin": "DraftTileAssembler" + } + }, + "load": { + "colors": { + "model": [ + 0.0, + 0.0, + 0.0 + ], + "rig": [ + 0.0, + 0.0, + 0.0 + ], + "pointcache": [ + 0.0, + 0.0, + 0.0 + ], + "animation": [ + 0.0, + 0.0, + 0.0 + ], + "ass": [ + 0.0, + 0.0, + 0.0 + ], + "camera": [ + 0.0, + 0.0, + 0.0 + ], + "fbx": [ + 0.0, + 0.0, + 0.0 + ], + "mayaAscii": [ + 0.0, + 0.0, + 0.0 + ], + "setdress": [ + 0.0, + 0.0, + 0.0 + ], + "layout": [ + 0.0, + 0.0, + 0.0 + ], + "vdbcache": [ + 0.0, + 0.0, + 0.0 + ], + "vrayproxy": [ + 0.0, + 0.0, + 0.0 + ], + "yeticache": [ + 0.0, + 0.0, + 0.0 + ], + "yetiRig": [ + 0.0, + 0.0, + 0.0 + ] } }, "workfile_build": { @@ -216,5 +306,6 @@ ] } ] - } + }, + "filter": {} } \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/maya/capture.json b/pype/settings/defaults/project_settings/maya/capture.json deleted file mode 100644 index b6c4893034..0000000000 --- a/pype/settings/defaults/project_settings/maya/capture.json +++ /dev/null @@ -1,108 +0,0 @@ -{ - "Codec": { - "compression": "jpg", - "format": "image", - "quality": 95 - }, - "Display Options": { - "background": [ - 0.7137254901960784, - 0.7137254901960784, - 0.7137254901960784 - ], - "backgroundBottom": [ - 0.7137254901960784, - 0.7137254901960784, - 0.7137254901960784 - ], - "backgroundTop": [ - 0.7137254901960784, - 0.7137254901960784, - 0.7137254901960784 - ], - "override_display": true - }, - "Generic": { - "isolate_view": true, - "off_screen": true - }, - "IO": { - "name": "", - "open_finished": false, - "raw_frame_numbers": false, - "recent_playblasts": [], - "save_file": false - }, - "PanZoom": { - "pan_zoom": true - }, - "Renderer": { - "rendererName": "vp2Renderer" - }, - "Resolution": { - "height": 1080, - "mode": "Custom", - "percent": 1.0, - "width": 1920 - }, - "Time Range": { - "end_frame": 25, - "frame": "", - "start_frame": 0, - "time": "Time Slider" - }, - "Viewport Options": { - "cameras": false, - "clipGhosts": false, - "controlVertices": false, - "deformers": false, - "dimensions": false, - "displayLights": 0, - "dynamicConstraints": false, - "dynamics": false, - "fluids": false, - "follicles": false, - "gpuCacheDisplayFilter": false, - "greasePencils": false, - "grid": false, - "hairSystems": false, - "handles": false, - "high_quality": true, - "hud": false, - "hulls": false, - "ikHandles": false, - "imagePlane": false, - "joints": false, - "lights": false, - "locators": false, - "manipulators": false, - "motionTrails": false, - "nCloths": false, - "nParticles": false, - "nRigids": false, - "nurbsCurves": false, - "nurbsSurfaces": false, - "override_viewport_options": true, - "particleInstancers": false, - "pivots": false, - "planes": false, - "pluginShapes": false, - "polymeshes": true, - "shadows": false, - "strokes": false, - "subdivSurfaces": false, - "textures": false, - "twoSidedLighting": true - }, - "Camera Options": { - "displayGateMask": false, - "displayResolution": false, - "displayFilmGate": false, - "displayFieldChart": false, - "displaySafeAction": false, - "displaySafeTitle": false, - "displayFilmPivot": false, - "displayFilmOrigin": false, - "overscan": 1.0 - } -} diff --git a/pype/settings/defaults/project_settings/muster/templates_mapping.json b/pype/settings/defaults/project_settings/muster/templates_mapping.json deleted file mode 100644 index 4edab9077d..0000000000 --- a/pype/settings/defaults/project_settings/muster/templates_mapping.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "3delight": 41, - "arnold": 46, - "arnold_sf": 57, - "gelato": 30, - "harware": 3, - "krakatoa": 51, - "file_layers": 7, - "mentalray": 2, - "mentalray_sf": 6, - "redshift": 55, - "renderman": 29, - "software": 1, - "software_sf": 5, - "turtle": 10, - "vector": 4, - "vray": 37, - "ffmpeg": 48 -} diff --git a/pype/settings/defaults/project_settings/nuke.json b/pype/settings/defaults/project_settings/nuke.json index 98b4f55aa4..5b9ef5c21c 100644 --- a/pype/settings/defaults/project_settings/nuke.json +++ b/pype/settings/defaults/project_settings/nuke.json @@ -1,36 +1,63 @@ { "create": { "CreateWriteRender": { - "fpath_template": "" + "fpath_template": "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}" }, "CreateWritePrerender": { - "fpath_template": "" + "fpath_template": "{work}/prerenders/nuke/{subset}/{subset}.{frame}.{ext}" } }, "publish": { "ExtractThumbnail": { "enabled": true, - "nodes": {} + "nodes": { + "Reformat": [ + [ + "type", + "to format" + ], + [ + "format", + "HD_1080" + ], + [ + "filter", + "Lanczos6" + ], + [ + "black_outside", + true + ], + [ + "pbb", + false + ] + ] + } }, "ValidateNukeWriteKnobs": { "enabled": true, - "knobs": {} + "knobs": { + "render": { + "review": true + } + } }, "ExtractReviewDataLut": { "enabled": true }, "ExtractReviewDataMov": { "enabled": true, - "viewer_lut_raw": true + "viewer_lut_raw": false }, "ExtractSlateFrame": { - "viewer_lut_raw": true + "viewer_lut_raw": false }, "NukeSubmitDeadline": { - "deadline_priority": 0, + "deadline_priority": 50, "deadline_pool": "", "deadline_pool_secondary": "", - "deadline_chunk_size": 0 + "deadline_chunk_size": 1 } }, "workfile_build": { @@ -58,5 +85,6 @@ "linked_assets": [] } ] - } + }, + "filter": {} } \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/plugins/celaction/publish.json b/pype/settings/defaults/project_settings/plugins/celaction/publish.json deleted file mode 100644 index 4cda2d5656..0000000000 --- a/pype/settings/defaults/project_settings/plugins/celaction/publish.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "ExtractCelactionDeadline": { - "enabled": true, - "deadline_department": "", - "deadline_priority": 60, - "deadline_pool": "", - "deadline_pool_secondary": "", - "deadline_group": "", - "deadline_chunk_size": 10 - } -} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/plugins/config.json b/pype/settings/defaults/project_settings/plugins/config.json deleted file mode 100644 index 9e26dfeeb6..0000000000 --- a/pype/settings/defaults/project_settings/plugins/config.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/plugins/ftrack/publish.json b/pype/settings/defaults/project_settings/plugins/ftrack/publish.json deleted file mode 100644 index 8570a400e8..0000000000 --- a/pype/settings/defaults/project_settings/plugins/ftrack/publish.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "IntegrateFtrackNote": { - "enabled": true, - "note_with_intent_template": "{intent}: {comment}", - "note_labels": [] - } -} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/plugins/global/create.json b/pype/settings/defaults/project_settings/plugins/global/create.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/pype/settings/defaults/project_settings/plugins/global/create.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/pype/settings/defaults/project_settings/plugins/global/filter.json b/pype/settings/defaults/project_settings/plugins/global/filter.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/pype/settings/defaults/project_settings/plugins/global/filter.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/pype/settings/defaults/project_settings/plugins/global/load.json b/pype/settings/defaults/project_settings/plugins/global/load.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/pype/settings/defaults/project_settings/plugins/global/load.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/pype/settings/defaults/project_settings/plugins/global/publish.json b/pype/settings/defaults/project_settings/plugins/global/publish.json deleted file mode 100644 index 676985797f..0000000000 --- a/pype/settings/defaults/project_settings/plugins/global/publish.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "IntegrateMasterVersion": { - "enabled": false - }, - "ExtractJpegEXR": { - "enabled": true, - "ffmpeg_args": { - "input": [ - "-gamma 2.2" - ], - "output": [] - } - }, - "ExtractReview": { - "enabled": true, - "profiles": [ - { - "families": [], - "hosts": [], - "outputs": { - "h264": { - "ext": "mp4", - "tags": [ - "burnin", - "ftrackreview" - ], - "ffmpeg_args": { - "video_filters": [], - "audio_filters": [], - "input": [ - "-gamma 2.2" - ], - "output": [ - "-pix_fmt yuv420p", - "-crf 18", - "-intra" - ] - }, - "filter": { - "families": [ - "render", - "review", - "ftrack" - ] - } - } - } - } - ] - }, - "ExtractBurnin": { - "enabled": true, - "options": { - "font_size": 42, - "opacity": 1, - "bg_opacity": 0, - "x_offset": 5, - "y_offset": 5, - "bg_padding": 5 - }, - "profiles": [ - { - "burnins": { - "burnin": { - "TOP_LEFT": "{yy}-{mm}-{dd}", - "TOP_RIGHT": "{anatomy[version]}", - "TOP_CENTERED": "", - "BOTTOM_RIGHT": "{frame_start}-{current_frame}-{frame_end}", - "BOTTOM_CENTERED": "{asset}", - "BOTTOM_LEFT": "{username}" - } - } - } - ] - }, - "IntegrateAssetNew": { - "template_name_profiles": { - "publish": { - "families": [], - "tasks": [] - }, - "render": { - "families": [ - "review", - "render", - "prerender" - ] - } - } - }, - "ProcessSubmittedJobOnFarm": { - "enabled": true, - "deadline_department": "", - "deadline_pool": "", - "deadline_group": "" - } -} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/plugins/maya/create.json b/pype/settings/defaults/project_settings/plugins/maya/create.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/pype/settings/defaults/project_settings/plugins/maya/create.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/pype/settings/defaults/project_settings/plugins/maya/filter.json b/pype/settings/defaults/project_settings/plugins/maya/filter.json deleted file mode 100644 index 83d6f05f31..0000000000 --- a/pype/settings/defaults/project_settings/plugins/maya/filter.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "Preset n1": { - "ValidateNoAnimation": false, - "ValidateShapeDefaultNames": false - }, - "Preset n2": { - "ValidateNoAnimation": false - } -} diff --git a/pype/settings/defaults/project_settings/plugins/maya/load.json b/pype/settings/defaults/project_settings/plugins/maya/load.json deleted file mode 100644 index 260fbb35ee..0000000000 --- a/pype/settings/defaults/project_settings/plugins/maya/load.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "colors": { - "model": [0.821, 0.518, 0.117], - "rig": [0.144, 0.443, 0.463], - "pointcache": [0.368, 0.821, 0.117], - "animation": [0.368, 0.821, 0.117], - "ass": [1.0, 0.332, 0.312], - "camera": [0.447, 0.312, 1.0], - "fbx": [1.0, 0.931, 0.312], - "mayaAscii": [0.312, 1.0, 0.747], - "setdress": [0.312, 1.0, 0.747], - "layout": [0.312, 1.0, 0.747], - "vdbcache": [0.312, 1.0, 0.428], - "vrayproxy": [0.258, 0.95, 0.541], - "yeticache": [0.2, 0.8, 0.3], - "yetiRig": [0, 0.8, 0.5] - } -} diff --git a/pype/settings/defaults/project_settings/plugins/maya/maya/maya_capture.json b/pype/settings/defaults/project_settings/plugins/maya/maya/maya_capture.json deleted file mode 100644 index 02e6a9b95d..0000000000 --- a/pype/settings/defaults/project_settings/plugins/maya/maya/maya_capture.json +++ /dev/null @@ -1,108 +0,0 @@ -{ - "Codec": { - "compression": "jpg", - "format": "image", - "quality": 95 - }, - "Display Options": { - "background": [ - 0.714, - 0.714, - 0.714 - ], - "backgroundBottom": [ - 0.714, - 0.714, - 0.714 - ], - "backgroundTop": [ - 0.714, - 0.714, - 0.714 - ], - "override_display": true - }, - "Generic": { - "isolate_view": true, - "off_screen": true - }, - "IO": { - "name": "", - "open_finished": false, - "raw_frame_numbers": false, - "recent_playblasts": [], - "save_file": false - }, - "PanZoom": { - "pan_zoom": true - }, - "Renderer": { - "rendererName": "vp2Renderer" - }, - "Resolution": { - "width": 1920, - "height": 1080, - "percent": 1.0, - "mode": "Custom" - }, - "Time Range": { - "start_frame": 0, - "end_frame": 25, - "frame": "", - "time": "Time Slider" - }, - "Viewport Options": { - "cameras": false, - "clipGhosts": false, - "controlVertices": false, - "deformers": false, - "dimensions": false, - "displayLights": 0, - "dynamicConstraints": false, - "dynamics": false, - "fluids": false, - "follicles": false, - "gpuCacheDisplayFilter": false, - "greasePencils": false, - "grid": false, - "hairSystems": false, - "handles": false, - "high_quality": true, - "hud": false, - "hulls": false, - "ikHandles": false, - "imagePlane": false, - "joints": false, - "lights": false, - "locators": false, - "manipulators": false, - "motionTrails": false, - "nCloths": false, - "nParticles": false, - "nRigids": false, - "nurbsCurves": false, - "nurbsSurfaces": false, - "override_viewport_options": true, - "particleInstancers": false, - "pivots": false, - "planes": false, - "pluginShapes": false, - "polymeshes": true, - "shadows": false, - "strokes": false, - "subdivSurfaces": false, - "textures": false, - "twoSidedLighting": true - }, - "Camera Options": { - "displayGateMask": false, - "displayResolution": false, - "displayFilmGate": false, - "displayFieldChart": false, - "displaySafeAction": false, - "displaySafeTitle": false, - "displayFilmPivot": false, - "displayFilmOrigin": false, - "overscan": 1.0 - } -} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/plugins/maya/maya/publish.json b/pype/settings/defaults/project_settings/plugins/maya/maya/publish.json deleted file mode 100644 index 486f0917e2..0000000000 --- a/pype/settings/defaults/project_settings/plugins/maya/maya/publish.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "ValidateModelName": { - "enabled": true, - "material_file": { - "windows": "", - "darwin": "", - "linux": "" - }, - "regex": "" - }, - "ValidateAssemblyName": { - "enabled": true - }, - "ValidateShaderName": { - "enabled": true, - "regex": "(?P.*)_(.*)_SHD" - }, - "ValidateMeshHasOverlappingUVs": { - "enabled": true - } -} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/plugins/maya/maya/workfile_build.json b/pype/settings/defaults/project_settings/plugins/maya/maya/workfile_build.json deleted file mode 100644 index 9e26dfeeb6..0000000000 --- a/pype/settings/defaults/project_settings/plugins/maya/maya/workfile_build.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/plugins/maya/publish.json b/pype/settings/defaults/project_settings/plugins/maya/publish.json deleted file mode 100644 index 2b3637ff80..0000000000 --- a/pype/settings/defaults/project_settings/plugins/maya/publish.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "ValidateModelName": { - "enabled": false, - "material_file": "/path/to/shader_name_definition.txt", - "regex": "(.*)_(\\d)*_(?P.*)_(GEO)" - }, - "ValidateAssemblyName": { - "enabled": false - }, - "ValidateShaderName": { - "enabled": false, - "regex": "(?P.*)_(.*)_SHD" - }, - "ValidateMeshHasOverlappingUVs": { - "enabled": false - } -} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/plugins/maya/workfile_build.json b/pype/settings/defaults/project_settings/plugins/maya/workfile_build.json deleted file mode 100644 index 1aad307895..0000000000 --- a/pype/settings/defaults/project_settings/plugins/maya/workfile_build.json +++ /dev/null @@ -1,131 +0,0 @@ -[{ - "tasks": [ - "lighting" - ], - "current_context": [{ - "subset_name_filters": [ - ".+[Mm]ain" - ], - "families": [ - "model" - ], - "repre_names": [ - "abc", - "ma" - ], - "loaders": [ - "ReferenceLoader" - ] - }, - { - "families": [ - "animation", - "pointcache" - ], - "repre_names": [ - "abc" - ], - "loaders": [ - "ReferenceLoader" - ] - }, - { - "families": [ - "rendersetup" - ], - "repre_names": [ - "json" - ], - "loaders": [ - "RenderSetupLoader" - ] - }, - { - "families": [ - "camera" - ], - "repre_names": [ - "abc" - ], - "loaders": [ - "ReferenceLoader" - ] - } - ], - "linked_assets": [{ - "families": [ - "setdress" - ], - "repre_names": [ - "ma" - ], - "loaders": [ - "ReferenceLoader" - ] - }, - { - "families": [ - "ass" - ], - "repre_names": [ - "ass" - ], - "loaders": [ - "assLoader" - ] - } - ] - }, - { - "tasks": [ - "animation" - ], - "current_context": [{ - "families": [ - "camera" - ], - "repre_names": [ - "abc", - "ma" - ], - "loaders": [ - "ReferenceLoader" - ] - }, - { - "families": [ - "audio" - ], - "repre_names": [ - "wav" - ], - "loaders": [ - "RenderSetupLoader" - ] - } - ], - "linked_assets": [{ - "families": [ - "setdress" - ], - "repre_names": [ - "proxy" - ], - "loaders": [ - "ReferenceLoader" - ] - }, - { - "families": [ - "rig" - ], - "repre_names": [ - "ass" - ], - "loaders": [ - "rigLoader" - ] - } - ] - } -] diff --git a/pype/settings/defaults/project_settings/plugins/nuke/create.json b/pype/settings/defaults/project_settings/plugins/nuke/create.json deleted file mode 100644 index 79ab665696..0000000000 --- a/pype/settings/defaults/project_settings/plugins/nuke/create.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "CreateWriteRender": { - "fpath_template": "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}" - }, - "CreateWritePrerender": { - "fpath_template": "{work}/prerenders/nuke/{subset}/{subset}.{frame}.{ext}" - } -} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/plugins/nuke/load.json b/pype/settings/defaults/project_settings/plugins/nuke/load.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/pype/settings/defaults/project_settings/plugins/nuke/load.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/pype/settings/defaults/project_settings/plugins/nuke/publish.json b/pype/settings/defaults/project_settings/plugins/nuke/publish.json deleted file mode 100644 index 50b5b27fc5..0000000000 --- a/pype/settings/defaults/project_settings/plugins/nuke/publish.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "ExtractThumbnail": { - "enabled": true, - "nodes": { - "Reformat": [ - [ - "type", - "to format" - ], - [ - "format", - "HD_1080" - ], - [ - "filter", - "Lanczos6" - ], - [ - "black_outside", - true - ], - [ - "pbb", - false - ] - ] - } - }, - "ValidateNukeWriteKnobs": { - "enabled": true, - "knobs": { - "render": { - "review": true - } - } - }, - "ExtractReviewDataLut": { - "enabled": true - }, - "ExtractReviewDataMov": { - "enabled": true, - "viewer_lut_raw": false - }, - "ExtractSlateFrame": { - "viewer_lut_raw": false - }, - "NukeSubmitDeadline": { - "deadline_priority": 50, - "deadline_pool": "", - "deadline_pool_secondary": "", - "deadline_chunk_size": 1 - } -} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/plugins/nuke/workfile_build.json b/pype/settings/defaults/project_settings/plugins/nuke/workfile_build.json deleted file mode 100644 index 4b48b46184..0000000000 --- a/pype/settings/defaults/project_settings/plugins/nuke/workfile_build.json +++ /dev/null @@ -1,23 +0,0 @@ -[ - { - "tasks": [ - "compositing" - ], - "current_context": [ - { - "families": [ - "render", - "plate" - ], - "repre_names": [ - "exr", - "dpx" - ], - "loaders": [ - "LoadSequence" - ] - } - ], - "linked_assets": [] - } -] \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/plugins/nukestudio/filter.json b/pype/settings/defaults/project_settings/plugins/nukestudio/filter.json deleted file mode 100644 index bd6a0dc1bd..0000000000 --- a/pype/settings/defaults/project_settings/plugins/nukestudio/filter.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "strict": { - "ValidateVersion": true, - "VersionUpWorkfile": true - }, - "benevolent": { - "ValidateVersion": false, - "VersionUpWorkfile": false - } -} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/plugins/nukestudio/publish.json b/pype/settings/defaults/project_settings/plugins/nukestudio/publish.json deleted file mode 100644 index d99a878c35..0000000000 --- a/pype/settings/defaults/project_settings/plugins/nukestudio/publish.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "CollectInstanceVersion": { - "enabled": false - }, - "ExtractReviewCutUpVideo": { - "enabled": true, - "tags_addition": [] - } -} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/plugins/resolve/create.json b/pype/settings/defaults/project_settings/plugins/resolve/create.json deleted file mode 100644 index 8ff5b15714..0000000000 --- a/pype/settings/defaults/project_settings/plugins/resolve/create.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "CreateShotClip": { - "clipName": "{track}{sequence}{shot}", - "folder": "takes", - "steps": 20 - } -} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/plugins/standalonepublisher/publish.json b/pype/settings/defaults/project_settings/plugins/standalonepublisher/publish.json deleted file mode 100644 index f7699ef9f7..0000000000 --- a/pype/settings/defaults/project_settings/plugins/standalonepublisher/publish.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "ExtractThumbnailSP": { - "ffmpeg_args": { - "input": [ - "-gamma 2.2" - ], - "output": [] - } - } -} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/plugins/test/create.json b/pype/settings/defaults/project_settings/plugins/test/create.json deleted file mode 100644 index fa0b2fc05f..0000000000 --- a/pype/settings/defaults/project_settings/plugins/test/create.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "MyTestCreator": { - "my_test_property": "B", - "active": false, - "new_property": "new", - "family": "new_family" - } -} diff --git a/pype/settings/defaults/project_settings/plugins/test/publish.json b/pype/settings/defaults/project_settings/plugins/test/publish.json deleted file mode 100644 index 3180dd5d8a..0000000000 --- a/pype/settings/defaults/project_settings/plugins/test/publish.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "MyTestPlugin": { - "label": "loaded from preset", - "optional": true, - "families": ["changed", "by", "preset"] - }, - "MyTestRemovedPlugin": { - "enabled": false - } -} diff --git a/pype/settings/defaults/project_settings/resolve.json b/pype/settings/defaults/project_settings/resolve.json index 646eb3a70b..cb7064ee76 100644 --- a/pype/settings/defaults/project_settings/resolve.json +++ b/pype/settings/defaults/project_settings/resolve.json @@ -1,9 +1,9 @@ { "create": { "CreateShotClip": { - "clipName": "", - "folder": "", - "steps": 0 + "clipName": "{track}{sequence}{shot}", + "folder": "takes", + "steps": 20 } } } \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/standalonepublisher.json b/pype/settings/defaults/project_settings/standalonepublisher.json new file mode 100644 index 0000000000..21ea3db586 --- /dev/null +++ b/pype/settings/defaults/project_settings/standalonepublisher.json @@ -0,0 +1,114 @@ +{ + "publish": { + "ExtractThumbnailSP": { + "ffmpeg_args": { + "input": [ + "gamma 2.2" + ], + "output": [] + } + } + }, + "create": { + "create_workfile": { + "name": "", + "label": "", + "family": "", + "icon": "", + "defaults": [], + "help": "" + }, + "create_model": { + "name": "", + "label": "", + "family": "", + "icon": "", + "defaults": [], + "help": "" + }, + "create_look": { + "name": "", + "label": "", + "family": "", + "icon": "", + "defaults": [], + "help": "" + }, + "create_rig": { + "name": "", + "label": "", + "family": "", + "icon": "", + "defaults": [], + "help": "" + }, + "create_pointcache": { + "name": "", + "label": "", + "family": "", + "icon": "", + "defaults": [], + "help": "" + }, + "create_plate": { + "name": "", + "label": "", + "family": "", + "icon": "", + "defaults": [], + "help": "" + }, + "create_camera": { + "name": "", + "label": "", + "family": "", + "icon": "", + "defaults": [], + "help": "" + }, + "create_mayaAscii": { + "name": "", + "label": "", + "family": "", + "icon": "", + "defaults": [], + "help": "" + }, + "create_editorial": { + "name": "", + "label": "", + "family": "", + "icon": "", + "defaults": [], + "help": "" + }, + "create_image": { + "name": "", + "label": "", + "family": "", + "icon": "", + "defaults": [], + "help": "" + }, + "create_matchmove": { + "name": "", + "label": "", + "family": "", + "icon": "", + "defaults": [], + "help": "" + }, + "other_families": { + "create_background": { + "name": "background", + "label": "Background", + "family": "background", + "icon": "image", + "defaults": [ + "Main" + ], + "help": "Layered background from PSD." + } + } + } +} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/standalonepublisher/families.json b/pype/settings/defaults/project_settings/standalonepublisher/families.json deleted file mode 100644 index d05941cc26..0000000000 --- a/pype/settings/defaults/project_settings/standalonepublisher/families.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "create_look": { - "name": "look", - "label": "Look", - "family": "look", - "icon": "paint-brush", - "defaults": ["Main"], - "help": "Shader connections defining shape look" - }, - "create_model": { - "name": "model", - "label": "Model", - "family": "model", - "icon": "cube", - "defaults": ["Main", "Proxy", "Sculpt"], - "help": "Polygonal static geometry" - }, - "create_workfile": { - "name": "workfile", - "label": "Workfile", - "family": "workfile", - "icon": "cube", - "defaults": ["Main"], - "help": "Working scene backup" - }, - "create_camera": { - "name": "camera", - "label": "Camera", - "family": "camera", - "icon": "video-camera", - "defaults": ["Main"], - "help": "Single baked camera" - }, - "create_pointcache": { - "name": "pointcache", - "label": "Pointcache", - "family": "pointcache", - "icon": "gears", - "defaults": ["Main"], - "help": "Alembic pointcache for animated data" - }, - "create_rig": { - "name": "rig", - "label": "Rig", - "family": "rig", - "icon": "wheelchair", - "defaults": ["Main"], - "help": "Artist-friendly rig with controls" - }, - "create_layout": { - "name": "layout", - "label": "Layout", - "family": "layout", - "icon": "cubes", - "defaults": ["Main"], - "help": "Simple scene for animators with camera" - }, - "create_plate": { - "name": "plate", - "label": "Plate", - "family": "plate", - "icon": "camera", - "defaults": ["Main", "BG", "Reference"], - "help": "Plates for compositors" - }, - "create_matchmove": { - "name": "matchmove", - "label": "Matchmove script", - "family": "matchmove", - "icon": "empire", - "defaults": ["Camera", "Object", "Mocap"], - "help": "Script exported from matchmoving application" - }, - "create_images": { - "name": "image", - "label": "Image file", - "family": "image", - "icon": "image", - "defaults": ["ConceptArt", "Reference", "Texture", "MattePaint"], - "help": "Holder for all kinds of image data" - }, - "create_editorial": { - "name": "editorial", - "label": "Editorial", - "family": "editorial", - "icon": "image", - "defaults": ["Main"], - "help": "Editorial files to generate shots." - } -} diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json b/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json index 7409b45533..0c14ff6f58 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json @@ -21,6 +21,10 @@ "type": "dict-invisible", "key": "project_settings", "children": [ + { + "type": "schema", + "name": "schema_project_global" + }, { "type": "schema", "name": "schema_project_ftrack" @@ -47,7 +51,7 @@ }, { "type": "schema", - "name": "schema_plugins" + "name": "schema_project_standalonepublisher" } ] } diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_plugins.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_plugins.json index 0ccdd79bc7..f04750ff83 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_plugins.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_plugins.json @@ -3,248 +3,7 @@ "collapsable": true, "key": "plugins", "label": "Plugins", - "children": [{ - "type": "dict", - "collapsable": true, - "key": "global", - "label": "Global", - "children": [{ - "type": "dict", - "collapsable": true, - "key": "publish", - "label": "Publish plugins", - "is_file": true, - "children": [{ - "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "IntegrateMasterVersion", - "label": "IntegrateMasterVersion", - "is_group": true, - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }] - }, { - "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "ExtractJpegEXR", - "label": "ExtractJpegEXR", - "is_group": true, - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "dict-invisible", - "key": "ffmpeg_args", - "children": [{ - "type": "list", - "object_type": "text", - "key": "input", - "label": "FFmpeg input arguments" - }, { - "type": "list", - "object_type": "text", - "key": "output", - "label": "FFmpeg output arguments" - }] - }] - }, { - "type": "dict", - "collapsable": true, - "key": "ExtractReview", - "label": "ExtractReview", - "checkbox_key": "enabled", - "is_group": true, - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "list", - "key": "profiles", - "label": "Profiles", - "object_type": { - "type": "dict", - "children": [{ - "key": "families", - "label": "Families", - "type": "list", - "object_type": "text" - }, { - "key": "hosts", - "label": "Hosts", - "type": "list", - "object_type": "text" - }, { - "type": "splitter" - }, { - "key": "outputs", - "label": "Output Definitions", - "type": "dict-modifiable", - "highlight_content": true, - "object_type": { - "type": "dict", - "children": [{ - "key": "ext", - "label": "Output extension", - "type": "text" - }, { - "key": "tags", - "label": "Tags", - "type": "enum", - "multiselection": true, - "enum_items": [{ - "burnin": "Add burnins" - }, - { - "ftrackreview": "Add to Ftrack" - }, - { - "delete": "Delete output" - }, - { - "slate-frame": "Add slate frame" - }, - { - "no-hnadles": "Skip handle frames" - } - ] - }, { - "key": "ffmpeg_args", - "label": "FFmpeg arguments", - "type": "dict", - "highlight_content": true, - "children": [{ - "key": "video_filters", - "label": "Video filters", - "type": "list", - "object_type": "text" - }, { - "type": "splitter" - }, { - "key": "audio_filters", - "label": "Audio filters", - "type": "list", - "object_type": "text" - }, { - "type": "splitter" - }, { - "key": "input", - "label": "Input arguments", - "type": "list", - "object_type": "text" - }, { - "type": "splitter" - }, { - "key": "output", - "label": "Output arguments", - "type": "list", - "object_type": "text" - }] - }, { - "key": "filter", - "label": "Additional output filtering", - "type": "dict", - "highlight_content": true, - "children": [{ - "key": "families", - "label": "Families", - "type": "list", - "object_type": "text" - }] - }] - } - }] - } - }] - }, { - "type": "dict", - "collapsable": true, - "key": "ExtractBurnin", - "label": "ExtractBurnin", - "checkbox_key": "enabled", - "is_group": true, - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "dict", - "collapsable": true, - "key": "options", - "label": "Burnin formating options", - "children": [{ - "type": "number", - "key": "font_size", - "label": "Font size" - }, { - "type": "number", - "key": "opacity", - "label": "Font opacity" - }, { - "type": "number", - "key": "bg_opacity", - "label": "Background opacity" - }, { - "type": "number", - "key": "x_offset", - "label": "X Offset" - }, { - "type": "number", - "key": "y_offset", - "label": "Y Offset" - }, { - "type": "number", - "key": "bg_padding", - "label": "Padding aroung text" - }] - }, { - "type": "raw-json", - "key": "profiles", - "label": "Burnin profiles" - }] - }, { - "type": "dict", - "collapsable": true, - "key": "IntegrateAssetNew", - "label": "IntegrateAssetNew", - "is_group": true, - "children": [{ - "type": "raw-json", - "key": "template_name_profiles", - "label": "template_name_profiles" - }] - }, { - "type": "dict", - "collapsable": true, - "key": "ProcessSubmittedJobOnFarm", - "label": "ProcessSubmittedJobOnFarm", - "checkbox_key": "enabled", - "is_group": true, - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "text", - "key": "deadline_department", - "label": "Deadline department" - }, { - "type": "text", - "key": "deadline_pool", - "label": "Deadline Pool" - }, { - "type": "text", - "key": "deadline_group", - "label": "Deadline Group" - }] - }] - }] - }, + "children": [ { "type": "dict", "collapsable": true, diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_global.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_global.json new file mode 100644 index 0000000000..ef8fc58257 --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_global.json @@ -0,0 +1,343 @@ +{ + "type": "dict", + "collapsable": true, + "key": "global", + "label": "Global", + "is_file": true, + "children": [ + { + "type": "dict", + "collapsable": true, + "key": "publish", + "label": "Publish plugins", + "is_file": true, + "children": [ + { + "type": "dict", + "collapsable": true, + "checkbox_key": "enabled", + "key": "IntegrateMasterVersion", + "label": "IntegrateMasterVersion", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }] + }, + { + "type": "dict", + "collapsable": true, + "checkbox_key": "enabled", + "key": "ExtractJpegEXR", + "label": "ExtractJpegEXR", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "dict-invisible", + "key": "ffmpeg_args", + "children": [ + { + "type": "list", + "object_type": "text", + "key": "input", + "label": "FFmpeg input arguments" + }, + { + "type": "list", + "object_type": "text", + "key": "output", + "label": "FFmpeg output arguments" + }] + }] + }, + { + "type": "dict", + "collapsable": true, + "key": "ExtractReview", + "label": "ExtractReview", + "checkbox_key": "enabled", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "list", + "key": "profiles", + "label": "Profiles", + "object_type": + { + "type": "dict", + "children": [ + { + "key": "families", + "label": "Families", + "type": "list", + "object_type": "text" + }, + { + "key": "hosts", + "label": "Hosts", + "type": "list", + "object_type": "text" + }, + { + "type": "splitter" + }, + { + "key": "outputs", + "label": "Output Definitions", + "type": "dict-modifiable", + "highlight_content": true, + "object_type": + { + "type": "dict", + "children": [ + { + "key": "ext", + "label": "Output extension", + "type": "text" + }, + { + "key": "tags", + "label": "Tags", + "type": "enum", + "multiselection": true, + "enum_items": [ + { + "burnin": "Add burnins" + }, + { + "ftrackreview": "Add to Ftrack" + }, + { + "delete": "Delete output" + }, + { + "slate-frame": "Add slate frame" + }, + { + "no-hnadles": "Skip handle frames" + }] + }, + { + "key": "ffmpeg_args", + "label": "FFmpeg arguments", + "type": "dict", + "highlight_content": true, + "children": [ + { + "key": "video_filters", + "label": "Video filters", + "type": "list", + "object_type": "text" + }, + { + "type": "splitter" + }, + { + "key": "audio_filters", + "label": "Audio filters", + "type": "list", + "object_type": "text" + }, + { + "type": "splitter" + }, + { + "key": "input", + "label": "Input arguments", + "type": "list", + "object_type": "text" + }, + { + "type": "splitter" + }, + { + "key": "output", + "label": "Output arguments", + "type": "list", + "object_type": "text" + }] + }, + { + "key": "filter", + "label": "Additional output filtering", + "type": "dict", + "highlight_content": true, + "children": [ + { + "key": "families", + "label": "Families", + "type": "list", + "object_type": "text" + }] + }] + } + }] + } + }] + }, + { + "type": "dict", + "collapsable": true, + "key": "ExtractBurnin", + "label": "ExtractBurnin", + "checkbox_key": "enabled", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "dict", + "collapsable": true, + "key": "options", + "label": "Burnin formating options", + "children": [ + { + "type": "number", + "key": "font_size", + "label": "Font size" + }, + { + "type": "number", + "key": "opacity", + "label": "Font opacity" + }, + { + "type": "number", + "key": "bg_opacity", + "label": "Background opacity" + }, + { + "type": "number", + "key": "x_offset", + "label": "X Offset" + }, + { + "type": "number", + "key": "y_offset", + "label": "Y Offset" + }, + { + "type": "number", + "key": "bg_padding", + "label": "Padding aroung text" + }] + }, + { + "type": "raw-json", + "key": "fields", + "label": "Burnin Fields" + }, + { + "type": "raw-json", + "key": "profiles", + "label": "Burnin profiles" + }] + }, + { + "type": "dict", + "collapsable": true, + "key": "IntegrateAssetNew", + "label": "IntegrateAssetNew", + "is_group": true, + "children": [ + { + "type": "raw-json", + "key": "template_name_profiles", + "label": "template_name_profiles" + }] + }, + { + "type": "dict", + "collapsable": true, + "key": "ProcessSubmittedJobOnFarm", + "label": "ProcessSubmittedJobOnFarm", + "checkbox_key": "enabled", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "text", + "key": "deadline_department", + "label": "Deadline department" + }, + { + "type": "text", + "key": "deadline_pool", + "label": "Deadline Pool" + }, + { + "type": "text", + "key": "deadline_group", + "label": "Deadline Group" + }, + { + "type": "text", + "key": "deadline_chunk_size", + "label": "Deadline Chunk Size" + }, + { + "type": "text", + "key": "deadline_priority", + "label": "Deadline Priotity" + }, + { + "type": "dict", + "key": "aov_filter", + "label": "Reviewable subsets filter", + "children": [ + { + "type": "list", + "key": "maya", + "label": "Maya", + "object_type":{ + "type":"text" + } + }, + { + "type": "list", + "key": "nuke", + "label": "Nuke", + "object_type":{ + "type":"text" + } + }, + { + "type": "list", + "key": "aftereffects", + "label": "After Effects", + "object_type":{ + "type":"text" + } + }, + { + "type": "list", + "key": "celaction", + "label": "Celaction", + "object_type":{ + "type":"text" + } + } + ] + }] + }] + }] +} diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_hiero.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_hiero.json index d80a6272c5..0f8475655c 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_hiero.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_hiero.json @@ -39,5 +39,10 @@ "label": "Tags addition" }] }] + }, + { + "type": "raw-json", + "key": "filter", + "label": "Publish GUI Filters" }] } diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_maya.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_maya.json index 0d8db078ea..d863941d1d 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_maya.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_maya.json @@ -10,10 +10,19 @@ }, { "type": "schema", - "name": "schema_maya_plugins" + "name": "schema_maya_publish" + }, + { + "type": "schema", + "name": "schema_maya_load" }, { "type": "schema", "name": "schema_workfile_build" + }, + { + "type": "raw-json", + "key": "filter", + "label": "Publish GUI Filters" }] } diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_nuke.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_nuke.json index f928ec6039..48d78cc422 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_nuke.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_nuke.json @@ -136,5 +136,10 @@ { "type": "schema", "name": "schema_workfile_build" + }, + { + "type": "raw-json", + "key": "filter", + "label": "Publish GUI Filters" }] } diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_standalonepublisher.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_standalonepublisher.json new file mode 100644 index 0000000000..5e07d82de6 --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_standalonepublisher.json @@ -0,0 +1,159 @@ +{ + "type": "dict", + "collapsable": true, + "key": "standalonepublisher", + "label": "Standalone Publisher", + "is_file": true, + "children": [ + { + "type": "dict", + "collapsable": true, + "key": "publish", + "label": "Publish plugins", + "is_file": true, + "children": [ + { + "type": "dict", + "collapsable": true, + "key": "ExtractThumbnailSP", + "label": "ExtractThumbnailSP", + "is_group": true, + "children": [ + { + "type": "dict", + "collapsable": false, + "key": "ffmpeg_args", + "label": "ffmpeg_args", + "children": [ + { + "type": "list", + "object_type": "text", + "key": "input", + "label": "input" + }, + { + "type": "list", + "object_type": "text", + "key": "output", + "label": "output" + }] + }] + }] + }, + { + "type": "dict", + "collapsable": true, + "key": "create", + "label": "Creator plugins", + "is_file": true, + "children": [ + { + "type": "schema_template", + "name": "template_creatorfamily", + "template_data": [ + { + "label": "Workfile", + "name": "workfile" + }] + }, + { + "type": "schema_template", + "name": "template_creatorfamily", + "template_data": [ + { + "label": "Model", + "name": "model" + }] + }, + { + "type": "schema_template", + "name": "template_creatorfamily", + "template_data": [ + { + "label": "Look", + "name": "look" + }] + }, + { + "type": "schema_template", + "name": "template_creatorfamily", + "template_data": [ + { + "label": "Rig", + "name": "rig" + }] + }, + { + "type": "schema_template", + "name": "template_creatorfamily", + "template_data": [ + { + "label": "Pointcache", + "name": "pointcache" + }] + }, + { + "type": "schema_template", + "name": "template_creatorfamily", + "template_data": [ + { + "label": "Plate", + "name": "plate" + }] + }, + { + "type": "schema_template", + "name": "template_creatorfamily", + "template_data": [ + { + "label": "Camera", + "name": "camera" + }] + }, + { + "type": "schema_template", + "name": "template_creatorfamily", + "template_data": [ + { + "label": "Maya Scene", + "name": "mayaAscii" + }] + }, + { + "type": "schema_template", + "name": "template_creatorfamily", + "template_data": [ + { + "label": "Editorial", + "name": "editorial" + }] + }, + { + "type": "schema_template", + "name": "template_creatorfamily", + "template_data": [ + { + "label": "Image", + "name": "image" + }] + }, + { + "type": "schema_template", + "name": "template_creatorfamily", + "template_data": [ + { + "label": "Matchmove", + "name": "matchmove" + }] + }, + { + "type": "dict-modifiable", + "key": "other_families", + "label": "Other Families", + "object_type": { + "type": "raw-json" + } + }] + }] + +} diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_load.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_load.json new file mode 100644 index 0000000000..0b96e63124 --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_load.json @@ -0,0 +1,142 @@ +{ + "type": "dict", + "collapsable": true, + "key": "load", + "label": "Loader plugins", + "is_file": true, + "children": [ + { + "type": "dict", + "collapsable": true, + "key": "colors", + "label": "Loaded Subsets Outliner Colors", + "children": [ + { + "type": "schema_template", + "name": "template_color", + "template_data": [ + { + "label": "Model", + "name": "model" + }] + }, + { + "type": "schema_template", + "name": "template_color", + "template_data": [ + { + "label": "Rig", + "name": "rig" + }] + }, + { + "type": "schema_template", + "name": "template_color", + "template_data": [ + { + "label": "Pointcache", + "name": "pointcache" + }] + }, + { + "type": "schema_template", + "name": "template_color", + "template_data": [ + { + "label": "Animation", + "name": "animation" + }] + }, + { + "type": "schema_template", + "name": "template_color", + "template_data": [ + { + "label": "Arnold Standin", + "name": "ass" + }] + }, + { + "type": "schema_template", + "name": "template_color", + "template_data": [ + { + "label": "Camera", + "name": "camera" + }] + }, + { + "type": "schema_template", + "name": "template_color", + "template_data": [ + { + "label": "FBX", + "name": "fbx" + }] + }, + { + "type": "schema_template", + "name": "template_color", + "template_data": [ + { + "label": "Maya Scene", + "name": "mayaAscii" + }] + }, + { + "type": "schema_template", + "name": "template_color", + "template_data": [ + { + "label": "Set Dress", + "name": "setdress" + }] + }, + { + "type": "schema_template", + "name": "template_color", + "template_data": [ + { + "label": "Layout", + "name": "layout" + }] + }, + { + "type": "schema_template", + "name": "template_color", + "template_data": [ + { + "label": "VDB Cache", + "name": "vdbcache" + }] + }, + { + "type": "schema_template", + "name": "template_color", + "template_data": [ + { + "label": "Vray Proxy", + "name": "vrayproxy" + }] + }, + { + "type": "schema_template", + "name": "template_color", + "template_data": [ + { + "label": "Yeti Cache", + "name": "yeticache" + }] + }, + { + "type": "schema_template", + "name": "template_color", + "template_data": [ + { + "label": "Yeti Rig", + "name": "yetiRig" + }] + } + ] + }] +} diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_plugins.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_plugins.json deleted file mode 100644 index 7ba9608610..0000000000 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_plugins.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "type": "dict", - "collapsable": true, - "key": "publish", - "label": "Publish plugins", - "is_file": true, - "children": [ - { - "type": "dict", - "collapsable": true, - "key": "ValidateModelName", - "label": "Validate Model Name", - "checkbox_key": "enabled", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, - { - "type": "label", - "label": "Path to material file defining list of material names to check. This is material name per line simple text file.
It will be checked against named group shader in your Validation regex.

For example:
^.*(?P=<shader>.+)_GEO

" - }, - { - "type": "path-widget", - "key": "material_file", - "label": "Material File", - "multiplatform": true, - "multipath": false - }, - { - "type": "text", - "key": "regex", - "label": "Validation regex" - } - ] - }, { - "type": "dict", - "collapsable": true, - "key": "ValidateAssemblyName", - "label": "Validate Assembly Name", - "checkbox_key": "enabled", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - } - ] - }, { - "type": "dict", - "collapsable": true, - "key": "ValidateShaderName", - "label": "ValidateShaderName", - "checkbox_key": "enabled", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "label", - "label": "Shader name regex can use named capture group asset to validate against current asset name.

Example:
^.*(?P=<asset>.+)_SHD

" - - }, { - "type": "text", - "key": "regex", - "label": "Validation regex" - } - ] - }, { - "type": "dict", - "collapsable": true, - "key": "ValidateMeshHasOverlappingUVs", - "label": "ValidateMeshHasOverlappingUVs", - "checkbox_key": "enabled", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - } - ] - } - ] - } diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_publish.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_publish.json new file mode 100644 index 0000000000..44972cad21 --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_publish.json @@ -0,0 +1,188 @@ +{ + "type": "dict", + "collapsable": true, + "key": "publish", + "label": "Publish plugins", + "is_file": true, + "children": [ + { + "type": "label", + "label": "Collectors" + }, + { + "type": "dict", + "collapsable": true, + "key": "CollectMayaRender", + "label": "Collect Render Layers", + "children": [ + { + "type": "boolean", + "key": "sync_workfile_version", + "label": "Sync render version with workfile" + }] + }, + { + "type": "splitter" + }, + { + "type": "label", + "label": "Collectors" + }, + { + "type": "dict", + "collapsable": true, + "key": "ValidateCameraAttributes", + "label": "Validate Camera Attributes", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }] + }, + { + "type": "dict", + "collapsable": true, + "key": "ValidateModelName", + "label": "Validate Model Name", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "label", + "label": "Path to material file defining list of material names to check. This is material name per line simple text file.
It will be checked against named group shader in your Validation regex.

For example:
^.*(?P=<shader>.+)_GEO

" + }, + { + "type": "path-widget", + "key": "material_file", + "label": "Material File", + "multiplatform": true, + "multipath": false + }, + { + "type": "text", + "key": "regex", + "label": "Validation regex" + }] + }, + { + "type": "dict", + "collapsable": true, + "key": "ValidateAssemblyName", + "label": "Validate Assembly Name", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }] + }, + { + "type": "dict", + "collapsable": true, + "key": "ValidateShaderName", + "label": "ValidateShaderName", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "label", + "label": "Shader name regex can use named capture group asset to validate against current asset name.

Example:
^.*(?P=<asset>.+)_SHD

" + + }, + { + "type": "text", + "key": "regex", + "label": "Validation regex" + }] + }, + { + "type": "dict", + "collapsable": true, + "key": "ValidateMeshHasOverlappingUVs", + "label": "ValidateMeshHasOverlappingUVs", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }] + }, + { + "type": "splitter" + }, + { + "type": "label", + "label": "Extractors" + }, + { + "type": "dict", + "collapsable": true, + "key": "ExtractCameraAlembic", + "label": "Extract camera to Alembic", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "label", + "label": "List of attributes that will be added to the baked alembic camera. Needs to be written in python list syntax.

For example:
[\"attributeName\", \"anotherAttribute\"]

" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "raw-json", + "key": "bake_attributes", + "label": "Bake Attributes" + + }] + }, + { + "type": "dict", + "collapsable": true, + "key": "MayaSubmitDeadline", + "label": "Submit maya job to deadline", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "enum", + "key": "tile_assembler_plugin", + "label": "Tile Assembler Plugin", + "multiselection": false, + "enum_items": [ + { + "DraftTileAssembler": "Draft Tile Assembler" + }, + { + "oiio": "Open Image IO" + }] + }] + }] +} diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/template_color.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/template_color.json new file mode 100644 index 0000000000..ac4313490b --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/template_color.json @@ -0,0 +1,28 @@ +[ + { + "type": "list-strict", + "key": "{name}", + "label": "{label}:", + "object_types": [ + { + "label": "Red", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 3 + }, { + "label": "Green", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 3 + }, { + "label": "Blue", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 3 + } + ] + } +] diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/template_creatorfamily.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/template_creatorfamily.json new file mode 100644 index 0000000000..eaeccf2c87 --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/template_creatorfamily.json @@ -0,0 +1,43 @@ +[ + { + "type": "dict", + "collapsable": true, + "key": "create_{name}", + "label": "{label}", + "children": [ + { + "type": "text", + "key": "name", + "label": "Name" + }, + { + "type": "text", + "key": "label", + "label": "Label" + }, + { + "type": "text", + "key": "family", + "label": "Family" + }, + { + "type": "text", + "key": "icon", + "label": "Icon" + }, + { + "type": "list", + "key": "defaults", + "label": "Defaults", + "object_type": { + "type": "text" + } + }, + { + "type": "text", + "key": "help", + "label": "Help" + } + ] + } +] From b304eef0f58cf727ff28bee678195a59564ec501 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 26 Nov 2020 15:07:27 +0100 Subject: [PATCH 075/279] feat(imageio): final schema and default setting for hiero and nuke --- .../defaults/project_anatomy/imageio.json | 161 +++-- .../schema_anatomy_imageio.json | 568 +++++++++--------- 2 files changed, 418 insertions(+), 311 deletions(-) diff --git a/pype/settings/defaults/project_anatomy/imageio.json b/pype/settings/defaults/project_anatomy/imageio.json index 8b934f810d..1adab0fc2b 100644 --- a/pype/settings/defaults/project_anatomy/imageio.json +++ b/pype/settings/defaults/project_anatomy/imageio.json @@ -1,42 +1,131 @@ { - "nuke": { - "root": { - "colorManagement": "Nuke", - "OCIO_config": "nuke-default", - "defaultViewerLUT": "Nuke Root LUTs", - "monitorLut": "sRGB", - "int8Lut": "sRGB", - "int16Lut": "sRGB", - "logLut": "Cineon", - "floatLut": "linear" - }, - "viewer": { - "viewerProcess": "sRGB" - }, - "write": { - "render": { - "colorspace": "linear" + "hosts": { + "hiero": { + "workfile": { + "ocioConfigName": "nuke-default", + "ocioconfigpath": { + "windows": [], + "darwin": [], + "linux": [] + }, + "workingSpace": "linear", + "sixteenBitLut": "sRGB", + "eightBitLut": "sRGB", + "floatLut": "linear", + "logLut": "Cineon", + "viewerLut": "sRGB", + "thumbnailLut": "sRGB" }, - "prerender": { - "colorspace": "linear" - }, - "still": { - "colorspace": "sRGB" + "regexInputs": { + "inputs": [ + { + "regex": "[^-a-zA-Z0-9](plateRef).*(?=mp4)", + "colorspace": "sRGB" + } + ] } }, - "read": { - "[^-a-zA-Z0-9]beauty[^-a-zA-Z0-9]": "linear", - "[^-a-zA-Z0-9](P|N|Z|crypto)[^-a-zA-Z0-9]": "linear", - "[^-a-zA-Z0-9](plateRef)[^-a-zA-Z0-9]": "sRGB" + "nuke": { + "workfile": { + "colorManagement": "Nuke", + "OCIO_config": "nuke-default", + "customOCIOConfigPath": { + "windows": [], + "darwin": [], + "linux": [] + }, + "workingSpaceLUT": "linear", + "monitorLut": "sRGB", + "int8Lut": "sRGB", + "int16Lut": "sRGB", + "logLut": "Cineon", + "floatLut": "linear" + }, + "nodes": { + "requiredNodes": [ + { + "plugins": [ + "CreateWriteRender" + ], + "nukeNodeClass": "Write", + "knobs": [ + { + "name": "file_type", + "value": "exr" + }, + { + "name": "datatype", + "value": "16 bit half" + }, + { + "name": "compression", + "value": "Zip (1 scanline)" + }, + { + "name": "autocrop", + "value": "True" + }, + { + "name": "tile_color", + "value": "0xff0000ff" + }, + { + "name": "channels", + "value": "rgb" + }, + { + "name": "colorspace", + "value": "linear" + } + ] + }, + { + "plugins": [ + "CreateWritePrerender" + ], + "nukeNodeClass": "Write", + "knobs": [ + { + "name": "file_type", + "value": "exr" + }, + { + "name": "datatype", + "value": "16 bit half" + }, + { + "name": "compression", + "value": "Zip (1 scanline)" + }, + { + "name": "autocrop", + "value": "False" + }, + { + "name": "tile_color", + "value": "0xff0000ff" + }, + { + "name": "channels", + "value": "rgb" + }, + { + "name": "colorspace", + "value": "linear" + } + ] + } + ], + "customNodes": [] + }, + "regexInputs": { + "inputs": [ + { + "regex": "[^-a-zA-Z0-9]beauty[^-a-zA-Z0-9]", + "colorspace": "linear" + } + ] + } } - }, - "maya": { - - }, - "houdini": { - - }, - "resolve": { - } -} +} \ No newline at end of file diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_anatomy_imageio.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_anatomy_imageio.json index d1a286b883..b7de6c5091 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_anatomy_imageio.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_anatomy_imageio.json @@ -1,280 +1,298 @@ { + "type": "dict", + "key": "imageio", + "label": "Color Management (Image i/o)", + "is_file": true, + "children": [{ + "key": "hosts", "type": "dict", - "key": "imageio", - "label": "Color Management (Image i/o)", - "is_file": true, - "children": [ - { - "key": "hosts", - "type": "dict", - "label": "Hosts", - "collapsed": false, - "collapsable": true, - "children": [ + "label": "Hosts", + "collapsed": false, + "collapsable": true, + "children": [{ + "key": "hiero", + "type": "dict", + "label": "Hiero", + "children": [{ + "key": "workfile", + "type": "dict", + "label": "Workfile", + "collapsable": false, + "children": [{ + "type": "form", + "children": [{ + "type": "enum", + "key": "ocioConfigName", + "label": "OpenColorIO Config", + "enum_items": [{ + "nuke-default": "nuke-default" + }, { - "key": "hiero", - "type": "dict", - "label": "Hiero", - "children": [ - { - "key": "workfile", - "type": "dict", - "label": "Workfile", - "collapsable": false, - "children": [ - { - "type": "form", - "children": [ - { - "type": "enum", - "key": "ocioConfigName", - "label": "OpenColorIO Config", - "enum_items": [ - {"nuke-default": "nuke-default"}, - {"aces_1.0.3": "aces_1.0.3"}, - {"aces_1.1": "aces_1.1"}, - {"custom": "custom"} - ] - }, { - "type": "path-widget", - "key": "ocioconfigpath", - "label": "Custom OCIO path", - "multiplatform": true, - "multipath": true - }, { - "type": "text", - "key": "workingSpace", - "label": "Working Space" - }, { - "type": "text", - "key": "sixteenBitLut", - "label": "16 Bit Files" - }, { - "type": "text", - "key": "eightBitLut", - "label": "8 Bit Files" - }, { - "type": "text", - "key": "floatLut", - "label": "Floating Point Files" - }, { - "type": "text", - "key": "logLut", - "label": "Log Files" - }, { - "type": "text", - "key": "viewerLut", - "label": "Viewer" - }, { - "type": "text", - "key": "thumbnailLut", - "label": "Thumbnails" - } - ] - } - ] - }, { - "key": "regexInputs", - "type": "dict", - "label": "Colorspace on Inputs by regex detection", - "collapsable": false, - "children": [ - { - "type": "list", - "key": "inputs", - "label": "", - "object_type": { - "type": "dict", - "children": [ - { - "type": "text", - "key": "regex", - "label": "Regex" - }, { - "type": "text", - "key": "colorspace", - "label": "Colorspace" - } - ] - } - } - ] - } - ] - }, { - "key": "nuke", - "type": "dict", - "label": "Nuke", - "children": [ - { - "key": "workfile", - "type": "dict", - "label": "Workfile", - "collapsable": false, - "is_group": true, - "children": [ - { - "type": "form", - "children": [ - { - "type": "enum", - "key": "colorManagement", - "label": "color management", - "enum_items": [ - {"Nuke": "Nuke"}, - {"OCIO": "OCIO"} - ] - }, { - "type": "enum", - "key": "OCIO_config", - "label": "OpenColorIO Config", - "enum_items": [ - {"nuke-default": "nuke-default"}, - {"spi-vfx": "spi-vfx"}, - {"spi-anim": "spi-anim"}, - {"aces_1.0.3": "aces_0.1.1"}, - {"aces_1.0.3": "aces_0.7.1"}, - {"aces_1.0.3": "aces_1.0.1"}, - {"aces_1.0.3": "aces_1.0.3"}, - {"aces_1.1": "aces_1.1"}, - {"custom": "custom"} - ] - }, { - "type": "path-widget", - "key": "customOCIOConfigPath", - "label": "Custom OCIO config path", - "multiplatform": true, - "multipath": true - }, { - "type": "text", - "key": "workingSpaceLUT", - "label": "Working Space" - }, { - "type": "text", - "key": "monitorLut", - "label": "monitor" - }, { - "type": "text", - "key": "int8Lut", - "label": "8-bit files" - }, { - "type": "text", - "key": "int16Lut", - "label": "16-bit files" - }, { - "type": "text", - "key": "logLut", - "label": "log files" - }, { - "type": "text", - "key": "floatLut", - "label": "float files" - } - ] - } - ] - }, { - "key": "nodes", - "type": "dict", - "label": "Nodes", - "collapsable": false, - "is_group": true, - "children": [ - { - "key": "CreateWriteRender", - "label": "CreateWriteRender", - "type": "dict", - "children": [ - { - "type": "text", - "key": "nukeNodeClass", - "label": "Nuke Node Class" - }, { - "type": "splitter" - }, - { - "key": "knobs", - "label": "Knobs", - "type": "list", - "object_type": { - "type": "dict-item", - "children": [ - { - "type": "text", - "key": "name", - "label": "Name" - }, { - "type": "text", - "key": "value", - "label": "Value" - } - ] - } - } - ] - }, { - "type": "list", - "key": "custom-items", - "label": "Custom Nodes", - "object_type": { - "type": "dict", - "children": [ - { - "key": "nodeCreateFamily", - "label": "Creator Family", - "type": "text" - }, { - "type": "text", - "key": "nodeClass", - "label": "Node Class" - }, { - "type": "splitter" - }, - { - "type": "dict-modifiable", - "key": "nodeKnobs", - "label": "Node Knobs", - "highlight_content": true, - "object_type": { - "type": "text", - "key": "nodeKnobValue" - } - } - ] - } - } - ] - }, { - "key": "regexInputs", - "type": "dict", - "label": "Colorspace on Inputs by regex detection", - "collapsable": false, - "children": [ - { - "type": "list", - "key": "inputs", - "label": "", - "object_type": { - "type": "dict", - "children": [ - { - "type": "text", - "key": "regex", - "label": "Regex" - }, { - "type": "text", - "key": "colorspace", - "label": "Colorspace" - } - ] - } - } - ] - } - ] + "aces_1.0.3": "aces_1.0.3" + }, + { + "aces_1.1": "aces_1.1" + }, + { + "custom": "custom" } - - ] - } - ] + ] + }, { + "type": "path-widget", + "key": "ocioconfigpath", + "label": "Custom OCIO path", + "multiplatform": true, + "multipath": true + }, { + "type": "text", + "key": "workingSpace", + "label": "Working Space" + }, { + "type": "text", + "key": "sixteenBitLut", + "label": "16 Bit Files" + }, { + "type": "text", + "key": "eightBitLut", + "label": "8 Bit Files" + }, { + "type": "text", + "key": "floatLut", + "label": "Floating Point Files" + }, { + "type": "text", + "key": "logLut", + "label": "Log Files" + }, { + "type": "text", + "key": "viewerLut", + "label": "Viewer" + }, { + "type": "text", + "key": "thumbnailLut", + "label": "Thumbnails" + }] + }] + }, { + "key": "regexInputs", + "type": "dict", + "label": "Colorspace on Inputs by regex detection", + "collapsable": true, + "children": [{ + "type": "list", + "key": "inputs", + "label": "", + "object_type": { + "type": "dict", + "children": [{ + "type": "text", + "key": "regex", + "label": "Regex" + }, { + "type": "text", + "key": "colorspace", + "label": "Colorspace" + }] + } + }] + }] + }, { + "key": "nuke", + "type": "dict", + "label": "Nuke", + "children": [{ + "key": "workfile", + "type": "dict", + "label": "Workfile", + "collapsable": false, + "is_group": true, + "children": [{ + "type": "form", + "children": [{ + "type": "enum", + "key": "colorManagement", + "label": "color management", + "enum_items": [{ + "Nuke": "Nuke" + }, + { + "OCIO": "OCIO" + } + ] + }, { + "type": "enum", + "key": "OCIO_config", + "label": "OpenColorIO Config", + "enum_items": [{ + "nuke-default": "nuke-default" + }, + { + "spi-vfx": "spi-vfx" + }, + { + "spi-anim": "spi-anim" + }, + { + "aces_1.0.3": "aces_0.1.1" + }, + { + "aces_1.0.3": "aces_0.7.1" + }, + { + "aces_1.0.3": "aces_1.0.1" + }, + { + "aces_1.0.3": "aces_1.0.3" + }, + { + "aces_1.1": "aces_1.1" + }, + { + "custom": "custom" + } + ] + }, { + "type": "path-widget", + "key": "customOCIOConfigPath", + "label": "Custom OCIO config path", + "multiplatform": true, + "multipath": true + }, { + "type": "text", + "key": "workingSpaceLUT", + "label": "Working Space" + }, { + "type": "text", + "key": "monitorLut", + "label": "monitor" + }, { + "type": "text", + "key": "int8Lut", + "label": "8-bit files" + }, { + "type": "text", + "key": "int16Lut", + "label": "16-bit files" + }, { + "type": "text", + "key": "logLut", + "label": "log files" + }, { + "type": "text", + "key": "floatLut", + "label": "float files" + }] + }] + }, { + "key": "nodes", + "type": "dict", + "label": "Nodes", + "collapsable": true, + "is_group": true, + "children": [ + { + "key": "requiredNodes", + "type": "list", + "label": "Required Nodes", + "object_type": { + "type": "dict", + "children": [{ + "type": "list", + "key": "plugins", + "label": "Used in plugins", + "object_type": { + "type": "text", + "key": "pluginClass", + "label": "Plugin Class" + } + }, { + "type": "text", + "key": "nukeNodeClass", + "label": "Nuke Node Class" + }, { + "type": "splitter" + }, { + "key": "knobs", + "label": "Knobs", + "type": "list", + "object_type": { + "type": "dict", + "children": [{ + "type": "text", + "key": "name", + "label": "Name" + }, { + "type": "text", + "key": "value", + "label": "Value" + }] + } + }] + } + }, { + "type": "list", + "key": "customNodes", + "label": "Custom Nodes", + "object_type": { + "type": "dict", + "children": [{ + "type": "list", + "key": "plugins", + "label": "Used in plugins", + "object_type": { + "type": "text", + "key": "pluginClass", + "label": "Plugin Class" + } + }, { + "type": "text", + "key": "nukeNodeClass", + "label": "Nuke Node Class" + }, { + "type": "splitter" + }, { + "key": "knobs", + "label": "Knobs", + "type": "list", + "object_type": { + "type": "dict", + "children": [{ + "type": "text", + "key": "name", + "label": "Name" + }, { + "type": "text", + "key": "value", + "label": "Value" + }] + } + }] + } + } + ] + }, { + "key": "regexInputs", + "type": "dict", + "label": "Colorspace on Inputs by regex detection", + "collapsable": true, + "children": [{ + "type": "list", + "key": "inputs", + "label": "", + "object_type": { + "type": "dict", + "children": [{ + "type": "text", + "key": "regex", + "label": "Regex" + }, { + "type": "text", + "key": "colorspace", + "label": "Colorspace" + }] + } + }] + }] + }] + }] } From 038945374962b6e08bbb9315a39aa66bd6673dcd Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 26 Nov 2020 15:10:48 +0100 Subject: [PATCH 076/279] fix(settings): removing examples --- .../settings/gui_schemas/system_schema/schema_main.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/schema_main.json b/pype/tools/settings/settings/gui_schemas/system_schema/schema_main.json index 3ec652c302..8e8798149c 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/schema_main.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/schema_main.json @@ -17,9 +17,6 @@ }, { "type": "schema", "name": "schema_tools" - }, { - "type": "schema", - "name": "example_schema" }] } ] From 1de4100adb17f7b5d51a309432264c6d4b50fdbe Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 26 Nov 2020 18:06:29 +0100 Subject: [PATCH 077/279] modifiable dictionary can use schemas and templates in --- pype/tools/settings/settings/widgets/lib.py | 87 ++++++++++++--------- 1 file changed, 52 insertions(+), 35 deletions(-) diff --git a/pype/tools/settings/settings/widgets/lib.py b/pype/tools/settings/settings/widgets/lib.py index 1ec46f92b9..f112a6e975 100644 --- a/pype/tools/settings/settings/widgets/lib.py +++ b/pype/tools/settings/settings/widgets/lib.py @@ -213,45 +213,62 @@ def _fill_inner_schemas(schema_data, schema_collection, schema_templates): if schema_data["type"] == "schema": raise ValueError("First item in schema data can't be schema.") - children = schema_data.get("children") - if not children: - return schema_data - - new_children = [] - for child in children: - child_type = child["type"] - if child_type == "schema": - schema_name = child["name"] - if schema_name not in schema_collection: - if schema_name in schema_templates: - raise KeyError(( - "Schema template \"{}\" is used as `schema`" - ).format(schema_name)) - raise KeyError( - "Schema \"{}\" was not found".format(schema_name) - ) - - filled_child = _fill_inner_schemas( - schema_collection[schema_name], - schema_collection, - schema_templates - ) - - elif child_type == "schema_template": - for filled_child in _fill_schema_template( - child, schema_collection, schema_templates - ): - new_children.append(filled_child) + children_key = "children" + object_type_key = "object_type" + for item_key in (children_key, object_type_key): + children = schema_data.get(item_key) + if not children: continue - else: - filled_child = _fill_inner_schemas( - child, schema_collection, schema_templates - ) + if object_type_key == item_key: + if not isinstance(children, dict): + continue + children = [children] - new_children.append(filled_child) + new_children = [] + for child in children: + child_type = child["type"] + if child_type == "schema": + schema_name = child["name"] + if schema_name not in schema_collection: + if schema_name in schema_templates: + raise KeyError(( + "Schema template \"{}\" is used as `schema`" + ).format(schema_name)) + raise KeyError( + "Schema \"{}\" was not found".format(schema_name) + ) - schema_data["children"] = new_children + filled_child = _fill_inner_schemas( + schema_collection[schema_name], + schema_collection, + schema_templates + ) + + elif child_type == "schema_template": + for filled_child in _fill_schema_template( + child, schema_collection, schema_templates + ): + new_children.append(filled_child) + continue + + else: + filled_child = _fill_inner_schemas( + child, schema_collection, schema_templates + ) + + new_children.append(filled_child) + + if item_key == object_type_key: + if len(new_children) != 1: + raise KeyError(( + "Failed to fill object type with type: {} | name {}" + ).format( + child_type, str(child.get("name")) + )) + new_children = new_children[0] + + schema_data[item_key] = new_children return schema_data From f0b50b9491ecb988778a6c272ddafc2fa7e639b8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 26 Nov 2020 18:07:35 +0100 Subject: [PATCH 078/279] added also separator to replace splitter --- pype/tools/settings/settings/widgets/item_types.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index be508d6617..02cd34416a 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -3771,6 +3771,7 @@ TypeToKlass.types["list-strict"] = ListStrictWidget TypeToKlass.types["enum"] = EnumeratorWidget TypeToKlass.types["dict-modifiable"] = ModifiableDict # DEPRECATED - remove when removed from schemas +TypeToKlass.types["splitter"] = SplitterWidget TypeToKlass.types["dict-item"] = DictWidget TypeToKlass.types["dict"] = DictWidget TypeToKlass.types["dict-invisible"] = DictInvisible @@ -3778,4 +3779,4 @@ TypeToKlass.types["path-widget"] = PathWidget TypeToKlass.types["form"] = DictFormWidget TypeToKlass.types["label"] = LabelWidget -TypeToKlass.types["splitter"] = SplitterWidget +TypeToKlass.types["separator"] = SplitterWidget From 0370600f86d00c4e3394da794003d1e294ce5970 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 26 Nov 2020 18:19:44 +0100 Subject: [PATCH 079/279] add burnin and families SP --- .../defaults/project_settings/global.json | 9 +- .../project_settings/standalonepublisher.json | 12 -- .../schema_project_global.json | 179 ++++++++++++------ .../schema_project_standalonepublisher.json | 150 ++++----------- .../schemas/template_creatorfamily.json | 43 ----- 5 files changed, 167 insertions(+), 226 deletions(-) delete mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/schemas/template_creatorfamily.json diff --git a/pype/settings/defaults/project_settings/global.json b/pype/settings/defaults/project_settings/global.json index b68f6d87bd..dd379b6180 100644 --- a/pype/settings/defaults/project_settings/global.json +++ b/pype/settings/defaults/project_settings/global.json @@ -57,17 +57,18 @@ "y_offset": 5, "bg_padding": 5 }, - "fields": {}, "profiles": [ { + "families": [], + "hosts": [], "burnins": { "burnin": { "TOP_LEFT": "{yy}-{mm}-{dd}", - "TOP_RIGHT": "{anatomy[version]}", "TOP_CENTERED": "", - "BOTTOM_RIGHT": "{frame_start}-{current_frame}-{frame_end}", + "TOP_RIGHT": "{anatomy[version]}", + "BOTTOM_LEFT": "{username}", "BOTTOM_CENTERED": "{asset}", - "BOTTOM_LEFT": "{username}" + "BOTTOM_RIGHT": "{frame_start}-{current_frame}-{frame_end}" } } } diff --git a/pype/settings/defaults/project_settings/standalonepublisher.json b/pype/settings/defaults/project_settings/standalonepublisher.json index 21ea3db586..85b7a55b9c 100644 --- a/pype/settings/defaults/project_settings/standalonepublisher.json +++ b/pype/settings/defaults/project_settings/standalonepublisher.json @@ -97,18 +97,6 @@ "icon": "", "defaults": [], "help": "" - }, - "other_families": { - "create_background": { - "name": "background", - "label": "Background", - "family": "background", - "icon": "image", - "defaults": [ - "Main" - ], - "help": "Layered background from PSD." - } } } } \ No newline at end of file diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_global.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_global.json index ef8fc58257..a4c98ecddb 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_global.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_global.json @@ -195,58 +195,120 @@ "checkbox_key": "enabled", "is_group": true, "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, - { - "type": "dict", - "collapsable": true, - "key": "options", - "label": "Burnin formating options", - "children": [ { - "type": "number", - "key": "font_size", - "label": "Font size" + "type": "boolean", + "key": "enabled", + "label": "Enabled" }, { - "type": "number", - "key": "opacity", - "label": "Font opacity" + "type": "dict", + "collapsable": true, + "key": "options", + "label": "Burnin formating options", + "children": [ + { + "type": "number", + "key": "font_size", + "label": "Font size" + }, + { + "type": "number", + "key": "opacity", + "label": "Font opacity" + }, + { + "type": "number", + "key": "bg_opacity", + "label": "Background opacity" + }, + { + "type": "number", + "key": "x_offset", + "label": "X Offset" + }, + { + "type": "number", + "key": "y_offset", + "label": "Y Offset" + }, + { + "type": "number", + "key": "bg_padding", + "label": "Padding aroung text" + }, + { + "type": "splitter" + }] }, + { - "type": "number", - "key": "bg_opacity", - "label": "Background opacity" - }, - { - "type": "number", - "key": "x_offset", - "label": "X Offset" - }, - { - "type": "number", - "key": "y_offset", - "label": "Y Offset" - }, - { - "type": "number", - "key": "bg_padding", - "label": "Padding aroung text" - }] - }, - { - "type": "raw-json", - "key": "fields", - "label": "Burnin Fields" - }, - { - "type": "raw-json", - "key": "profiles", - "label": "Burnin profiles" - }] + "type": "list", + "key": "profiles", + "label": "Profiles", + "object_type": + { + "type": "dict", + "children": [ + { + "key": "families", + "label": "Families", + "type": "list", + "object_type": "text" + }, + { + "key": "hosts", + "label": "Hosts", + "type": "list", + "object_type": "text" + }, + { + "type": "splitter" + }, + { + "key": "burnins", + "label": "Burnins", + "type": "dict-modifiable", + "highlight_content": true, + "collapsable": false, + "object_type": + { + "type": "dict", + "children": [ + { + "key": "TOP_LEFT", + "label": "Top Left", + "type": "text" + }, + { + "key": "TOP_CENTERED", + "label": "Top Centered", + "type": "text" + }, + { + "key": "TOP_RIGHT", + "label": "top Right", + "type": "text" + }, + { + "key": "BOTTOM_LEFT", + "label": "Bottom Left", + "type": "text" + }, + { + "key": "BOTTOM_CENTERED", + "label": "Bottom Centered", + "type": "text" + }, + { + "key": "BOTTOM_RIGHT", + "label": "BottomRight", + "type": "text" + }] + } + }] + } + } + ] }, { "type": "dict", @@ -308,35 +370,38 @@ "type": "list", "key": "maya", "label": "Maya", - "object_type":{ - "type":"text" + "object_type": + { + "type": "text" } }, { "type": "list", "key": "nuke", "label": "Nuke", - "object_type":{ - "type":"text" + "object_type": + { + "type": "text" } }, { "type": "list", "key": "aftereffects", "label": "After Effects", - "object_type":{ - "type":"text" + "object_type": + { + "type": "text" } }, { "type": "list", "key": "celaction", "label": "Celaction", - "object_type":{ - "type":"text" + "object_type": + { + "type": "text" } - } - ] + }] }] }] }] diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_standalonepublisher.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_standalonepublisher.json index 5e07d82de6..4a6e5f76ec 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_standalonepublisher.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_standalonepublisher.json @@ -41,119 +41,49 @@ }] }, { - "type": "dict", + "type": "dict-modifiable", "collapsable": true, "key": "create", "label": "Creator plugins", "is_file": true, - "children": [ - { - "type": "schema_template", - "name": "template_creatorfamily", - "template_data": [ - { - "label": "Workfile", - "name": "workfile" - }] - }, - { - "type": "schema_template", - "name": "template_creatorfamily", - "template_data": [ - { - "label": "Model", - "name": "model" - }] - }, - { - "type": "schema_template", - "name": "template_creatorfamily", - "template_data": [ - { - "label": "Look", - "name": "look" - }] - }, - { - "type": "schema_template", - "name": "template_creatorfamily", - "template_data": [ - { - "label": "Rig", - "name": "rig" - }] - }, - { - "type": "schema_template", - "name": "template_creatorfamily", - "template_data": [ - { - "label": "Pointcache", - "name": "pointcache" - }] - }, - { - "type": "schema_template", - "name": "template_creatorfamily", - "template_data": [ - { - "label": "Plate", - "name": "plate" - }] - }, - { - "type": "schema_template", - "name": "template_creatorfamily", - "template_data": [ - { - "label": "Camera", - "name": "camera" - }] - }, - { - "type": "schema_template", - "name": "template_creatorfamily", - "template_data": [ - { - "label": "Maya Scene", - "name": "mayaAscii" - }] - }, - { - "type": "schema_template", - "name": "template_creatorfamily", - "template_data": [ - { - "label": "Editorial", - "name": "editorial" - }] - }, - { - "type": "schema_template", - "name": "template_creatorfamily", - "template_data": [ - { - "label": "Image", - "name": "image" - }] - }, - { - "type": "schema_template", - "name": "template_creatorfamily", - "template_data": [ - { - "label": "Matchmove", - "name": "matchmove" - }] - }, - { - "type": "dict-modifiable", - "key": "other_families", - "label": "Other Families", - "object_type": { - "type": "raw-json" - } - }] + "object_type": + { + "type": "dict", + "children": [ + { + "type": "text", + "key": "name", + "label": "Name" + }, + { + "type": "text", + "key": "label", + "label": "Label" + }, + { + "type": "text", + "key": "family", + "label": "Family" + }, + { + "type": "text", + "key": "icon", + "label": "Icon" + }, + { + "type": "list", + "key": "defaults", + "label": "Defaults", + "object_type": + { + "type": "text" + } + }, + { + "type": "text", + "key": "help", + "label": "Help" + }] + } }] - } diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/template_creatorfamily.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/template_creatorfamily.json deleted file mode 100644 index eaeccf2c87..0000000000 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/template_creatorfamily.json +++ /dev/null @@ -1,43 +0,0 @@ -[ - { - "type": "dict", - "collapsable": true, - "key": "create_{name}", - "label": "{label}", - "children": [ - { - "type": "text", - "key": "name", - "label": "Name" - }, - { - "type": "text", - "key": "label", - "label": "Label" - }, - { - "type": "text", - "key": "family", - "label": "Family" - }, - { - "type": "text", - "key": "icon", - "label": "Icon" - }, - { - "type": "list", - "key": "defaults", - "label": "Defaults", - "object_type": { - "type": "text" - } - }, - { - "type": "text", - "key": "help", - "label": "Help" - } - ] - } -] From 34b568304eae58866ff7ffdf1107f9818f95d046 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 26 Nov 2020 18:20:26 +0100 Subject: [PATCH 080/279] fix(hiero): trimming review with clip event number --- pype/plugins/hiero/publish/extract_review_cutup.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pype/plugins/hiero/publish/extract_review_cutup.py b/pype/plugins/hiero/publish/extract_review_cutup.py index ace6bc88d3..210def3448 100644 --- a/pype/plugins/hiero/publish/extract_review_cutup.py +++ b/pype/plugins/hiero/publish/extract_review_cutup.py @@ -23,6 +23,8 @@ class ExtractReviewCutUp(pype.api.Extractor): def process(self, instance): inst_data = instance.data asset = inst_data['asset'] + item = inst_data['item'] + event_number = int(item.eventNumber()) # get representation and loop them representations = inst_data["representations"] @@ -97,7 +99,7 @@ class ExtractReviewCutUp(pype.api.Extractor): index = 0 for image in collection: dst_file_num = frame_start + index - dst_file_name = head + str(padding % dst_file_num) + tail + dst_file_name = str(event_number) + head + str(padding % dst_file_num) + tail src = os.path.join(staging_dir, image) dst = os.path.join(full_output_dir, dst_file_name) self.log.info("Creating temp hardlinks: {}".format(dst)) From 61e703f13a7c9e65e9d7bdb911da70b95524e411 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 26 Nov 2020 18:23:08 +0100 Subject: [PATCH 081/279] hound(hiero): improving variable building --- pype/plugins/hiero/publish/extract_review_cutup.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pype/plugins/hiero/publish/extract_review_cutup.py b/pype/plugins/hiero/publish/extract_review_cutup.py index 210def3448..87e584d0b0 100644 --- a/pype/plugins/hiero/publish/extract_review_cutup.py +++ b/pype/plugins/hiero/publish/extract_review_cutup.py @@ -99,7 +99,12 @@ class ExtractReviewCutUp(pype.api.Extractor): index = 0 for image in collection: dst_file_num = frame_start + index - dst_file_name = str(event_number) + head + str(padding % dst_file_num) + tail + dst_file_name = "".join([ + str(event_number), + head, + str(padding % dst_file_num), + tail + ]) src = os.path.join(staging_dir, image) dst = os.path.join(full_output_dir, dst_file_name) self.log.info("Creating temp hardlinks: {}".format(dst)) From aff450992a9547732c429d68efc22e9ad1b0e276 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 26 Nov 2020 18:31:58 +0100 Subject: [PATCH 082/279] remove old dict-invisible --- .../gui_schemas/projects_schema/schema_project_global.json | 2 +- .../system_schema/module_settings/schema_ftrack.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_global.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_global.json index a4c98ecddb..6fdc6a23a5 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_global.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_global.json @@ -40,7 +40,7 @@ "label": "Enabled" }, { - "type": "dict-invisible", + "type": "dict", "key": "ffmpeg_args", "children": [ { diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json b/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json index 9a0d36ad06..8dd219e98e 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json @@ -142,7 +142,7 @@ }, { "key": "intent", - "type": "dict-invisible", + "type": "dict", "children": [{ "type": "label", "label": "Intent" From 327ff56ded1e8b47c5e6c4d6828f884d804d95d9 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 26 Nov 2020 19:23:01 +0100 Subject: [PATCH 083/279] filled publish filter settings --- .../defaults/project_settings/hiero.json | 15 +- .../defaults/project_settings/maya.json | 10 +- .../defaults/project_settings/nuke.json | 2 +- .../project_settings/standalonepublisher.json | 152 ++++++++++-------- .../{global => }/applications.json | 0 .../system_settings/{global => }/general.json | 0 .../system_settings/{global => }/hosts.json | 0 .../system_settings/{global => }/intent.json | 0 .../system_settings/{global => }/modules.json | 0 .../standalone_publish/families.json | 90 ----------- .../system_settings/{global => }/tools.json | 0 .../projects_schema/schema_project_hiero.json | 5 +- .../projects_schema/schema_project_maya.json | 5 +- .../projects_schema/schema_project_nuke.json | 5 +- .../schemas/schema_publish_gui_filter.json | 12 ++ .../system_schema/schema_main.json | 32 ++-- 16 files changed, 127 insertions(+), 201 deletions(-) rename pype/settings/defaults/system_settings/{global => }/applications.json (100%) rename pype/settings/defaults/system_settings/{global => }/general.json (100%) rename pype/settings/defaults/system_settings/{global => }/hosts.json (100%) rename pype/settings/defaults/system_settings/{global => }/intent.json (100%) rename pype/settings/defaults/system_settings/{global => }/modules.json (100%) delete mode 100644 pype/settings/defaults/system_settings/standalone_publish/families.json rename pype/settings/defaults/system_settings/{global => }/tools.json (100%) create mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_publish_gui_filter.json diff --git a/pype/settings/defaults/project_settings/hiero.json b/pype/settings/defaults/project_settings/hiero.json index e7e6350c29..e4e65eedd3 100644 --- a/pype/settings/defaults/project_settings/hiero.json +++ b/pype/settings/defaults/project_settings/hiero.json @@ -5,17 +5,10 @@ }, "ExtractReviewCutUpVideo": { "enabled": true, - "tags_addition": [] + "tags_addition": [ + "review" + ] } }, - "filter": { - "strict": { - "ValidateVersion": true, - "VersionUpWorkfile": true - }, - "benevolent": { - "ValidateVersion": false, - "VersionUpWorkfile": false - } - } + "filters": {} } \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/maya.json b/pype/settings/defaults/project_settings/maya.json index f8315dc129..afc4442d0f 100644 --- a/pype/settings/defaults/project_settings/maya.json +++ b/pype/settings/defaults/project_settings/maya.json @@ -307,5 +307,13 @@ } ] }, - "filter": {} + "filters": { + "preset 1": { + "ValidateNoAnimation": false, + "ValidateShapeDefaultNames": false + }, + "preset 2": { + "ValidateNoAnimation": false + } + } } \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/nuke.json b/pype/settings/defaults/project_settings/nuke.json index 5b9ef5c21c..873f249769 100644 --- a/pype/settings/defaults/project_settings/nuke.json +++ b/pype/settings/defaults/project_settings/nuke.json @@ -86,5 +86,5 @@ } ] }, - "filter": {} + "filters": {} } \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/standalonepublisher.json b/pype/settings/defaults/project_settings/standalonepublisher.json index 85b7a55b9c..2b5db54a4f 100644 --- a/pype/settings/defaults/project_settings/standalonepublisher.json +++ b/pype/settings/defaults/project_settings/standalonepublisher.json @@ -11,92 +11,104 @@ }, "create": { "create_workfile": { - "name": "", - "label": "", - "family": "", - "icon": "", - "defaults": [], - "help": "" + "name": "workfile", + "label": "Workfile", + "family": "workfile", + "icon": "cube", + "defaults": [ + "Main" + ], + "help": "Working scene backup" }, "create_model": { - "name": "", - "label": "", - "family": "", - "icon": "", - "defaults": [], - "help": "" - }, - "create_look": { - "name": "", - "label": "", - "family": "", - "icon": "", - "defaults": [], - "help": "" + "name": "mode", + "label": "Model", + "family": "model", + "icon": "cube", + "defaults": [ + "Main" + ], + "help": "Polygonal static geometry" }, "create_rig": { - "name": "", - "label": "", - "family": "", - "icon": "", - "defaults": [], - "help": "" + "name": "rig", + "label": "Rig", + "family": "rig", + "icon": "wheelchair", + "defaults": [ + "Main", + "Cloth" + ], + "help": "Artist-friendly rig with controls" }, "create_pointcache": { - "name": "", - "label": "", - "family": "", - "icon": "", - "defaults": [], - "help": "" + "name": "pointcache", + "label": "Pointcache", + "family": "pointcache", + "icon": "gears", + "defaults": [ + "Main" + ], + "help": "Alembic pointcache for animated data" }, "create_plate": { - "name": "", - "label": "", - "family": "", - "icon": "", - "defaults": [], - "help": "" + "name": "plate", + "label": "Plate", + "family": "plate", + "icon": "camera", + "defaults": [ + "Main", + "BG", + "Animatic", + "Reference", + "Offline" + ], + "help": "Footage for composting or reference" }, "create_camera": { - "name": "", - "label": "", - "family": "", - "icon": "", - "defaults": [], - "help": "" - }, - "create_mayaAscii": { - "name": "", - "label": "", - "family": "", - "icon": "", - "defaults": [], - "help": "" + "name": "camera", + "label": "Camera", + "family": "camera", + "icon": "camera", + "defaults": [ + "Main" + ], + "help": "video-camera" }, "create_editorial": { - "name": "", - "label": "", - "family": "", - "icon": "", - "defaults": [], - "help": "" + "name": "editorial", + "label": "Editorial", + "family": "editorial", + "icon": "image", + "defaults": [ + "Main" + ], + "help": "Editorial files to generate shots." }, "create_image": { - "name": "", - "label": "", - "family": "", - "icon": "", - "defaults": [], - "help": "" + "name": "image", + "label": "Image file", + "family": "image", + "icon": "image", + "defaults": [ + "Reference", + "Texture", + "ConceptArt", + "MattePaint" + ], + "help": "Holder for all kinds of image data" }, "create_matchmove": { - "name": "", - "label": "", - "family": "", - "icon": "", - "defaults": [], - "help": "" + "name": "matchmove", + "label": "Matchmove script", + "family": "matchmove", + "icon": "empire", + "defaults": [ + "Camera", + "Object", + "Mocap" + ], + "help": "Script exported from matchmoving application" } } } \ No newline at end of file diff --git a/pype/settings/defaults/system_settings/global/applications.json b/pype/settings/defaults/system_settings/applications.json similarity index 100% rename from pype/settings/defaults/system_settings/global/applications.json rename to pype/settings/defaults/system_settings/applications.json diff --git a/pype/settings/defaults/system_settings/global/general.json b/pype/settings/defaults/system_settings/general.json similarity index 100% rename from pype/settings/defaults/system_settings/global/general.json rename to pype/settings/defaults/system_settings/general.json diff --git a/pype/settings/defaults/system_settings/global/hosts.json b/pype/settings/defaults/system_settings/hosts.json similarity index 100% rename from pype/settings/defaults/system_settings/global/hosts.json rename to pype/settings/defaults/system_settings/hosts.json diff --git a/pype/settings/defaults/system_settings/global/intent.json b/pype/settings/defaults/system_settings/intent.json similarity index 100% rename from pype/settings/defaults/system_settings/global/intent.json rename to pype/settings/defaults/system_settings/intent.json diff --git a/pype/settings/defaults/system_settings/global/modules.json b/pype/settings/defaults/system_settings/modules.json similarity index 100% rename from pype/settings/defaults/system_settings/global/modules.json rename to pype/settings/defaults/system_settings/modules.json diff --git a/pype/settings/defaults/system_settings/standalone_publish/families.json b/pype/settings/defaults/system_settings/standalone_publish/families.json deleted file mode 100644 index d05941cc26..0000000000 --- a/pype/settings/defaults/system_settings/standalone_publish/families.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "create_look": { - "name": "look", - "label": "Look", - "family": "look", - "icon": "paint-brush", - "defaults": ["Main"], - "help": "Shader connections defining shape look" - }, - "create_model": { - "name": "model", - "label": "Model", - "family": "model", - "icon": "cube", - "defaults": ["Main", "Proxy", "Sculpt"], - "help": "Polygonal static geometry" - }, - "create_workfile": { - "name": "workfile", - "label": "Workfile", - "family": "workfile", - "icon": "cube", - "defaults": ["Main"], - "help": "Working scene backup" - }, - "create_camera": { - "name": "camera", - "label": "Camera", - "family": "camera", - "icon": "video-camera", - "defaults": ["Main"], - "help": "Single baked camera" - }, - "create_pointcache": { - "name": "pointcache", - "label": "Pointcache", - "family": "pointcache", - "icon": "gears", - "defaults": ["Main"], - "help": "Alembic pointcache for animated data" - }, - "create_rig": { - "name": "rig", - "label": "Rig", - "family": "rig", - "icon": "wheelchair", - "defaults": ["Main"], - "help": "Artist-friendly rig with controls" - }, - "create_layout": { - "name": "layout", - "label": "Layout", - "family": "layout", - "icon": "cubes", - "defaults": ["Main"], - "help": "Simple scene for animators with camera" - }, - "create_plate": { - "name": "plate", - "label": "Plate", - "family": "plate", - "icon": "camera", - "defaults": ["Main", "BG", "Reference"], - "help": "Plates for compositors" - }, - "create_matchmove": { - "name": "matchmove", - "label": "Matchmove script", - "family": "matchmove", - "icon": "empire", - "defaults": ["Camera", "Object", "Mocap"], - "help": "Script exported from matchmoving application" - }, - "create_images": { - "name": "image", - "label": "Image file", - "family": "image", - "icon": "image", - "defaults": ["ConceptArt", "Reference", "Texture", "MattePaint"], - "help": "Holder for all kinds of image data" - }, - "create_editorial": { - "name": "editorial", - "label": "Editorial", - "family": "editorial", - "icon": "image", - "defaults": ["Main"], - "help": "Editorial files to generate shots." - } -} diff --git a/pype/settings/defaults/system_settings/global/tools.json b/pype/settings/defaults/system_settings/tools.json similarity index 100% rename from pype/settings/defaults/system_settings/global/tools.json rename to pype/settings/defaults/system_settings/tools.json diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_hiero.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_hiero.json index 0f8475655c..834dc0bb3d 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_hiero.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_hiero.json @@ -41,8 +41,7 @@ }] }, { - "type": "raw-json", - "key": "filter", - "label": "Publish GUI Filters" + "type": "schema", + "name": "schema_publish_gui_filter" }] } diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_maya.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_maya.json index d863941d1d..a71cfb1e09 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_maya.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_maya.json @@ -21,8 +21,7 @@ "name": "schema_workfile_build" }, { - "type": "raw-json", - "key": "filter", - "label": "Publish GUI Filters" + "type": "schema", + "name": "schema_publish_gui_filter" }] } diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_nuke.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_nuke.json index 48d78cc422..3870fbe8bd 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_nuke.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_nuke.json @@ -138,8 +138,7 @@ "name": "schema_workfile_build" }, { - "type": "raw-json", - "key": "filter", - "label": "Publish GUI Filters" + "type": "schema", + "name": "schema_publish_gui_filter" }] } diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_publish_gui_filter.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_publish_gui_filter.json new file mode 100644 index 0000000000..f2385996eb --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_publish_gui_filter.json @@ -0,0 +1,12 @@ +{ + "type": "dict-modifiable", + "collapsable": true, + "key": "filters", + "label": "Publish GUI Filters", + "is_file": true, + "object_type": + { + "type": "raw-json", + "label": "Plugins" + } +} diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/schema_main.json b/pype/tools/settings/settings/gui_schemas/system_schema/schema_main.json index 039d00401c..d5c7402dcf 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/schema_main.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/schema_main.json @@ -1,23 +1,17 @@ { "key": "system", "type": "dict", - "children": [ - { - "type": "dict", - "key": "global", - "children": [{ - "type": "schema", - "name": "schema_general" - },{ - "type": "schema", - "name": "schema_modules" - }, { - "type": "schema", - "name": "schema_applications" - }, { - "type": "schema", - "name": "schema_tools" - }] - } - ] + "children": [{ + "type": "schema", + "name": "schema_general" + },{ + "type": "schema", + "name": "schema_modules" + }, { + "type": "schema", + "name": "schema_applications" + }, { + "type": "schema", + "name": "schema_tools" + }] } From 50078fa0696ce3b53df973a0d7c3229f58994bd8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 02:32:07 +0100 Subject: [PATCH 084/279] moved validation of ftrack c ustom attributes to ftrack plugins --- .../publish/validate_custom_ftrack_attributes.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pype/plugins/{global => ftrack}/publish/validate_custom_ftrack_attributes.py (100%) diff --git a/pype/plugins/global/publish/validate_custom_ftrack_attributes.py b/pype/plugins/ftrack/publish/validate_custom_ftrack_attributes.py similarity index 100% rename from pype/plugins/global/publish/validate_custom_ftrack_attributes.py rename to pype/plugins/ftrack/publish/validate_custom_ftrack_attributes.py From 5bd3974dc7935721636eb3251c6986a8ed50cc74 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 02:35:17 +0100 Subject: [PATCH 085/279] delivery action returns bool or message on launch end --- pype/modules/ftrack/actions/action_delivery.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pype/modules/ftrack/actions/action_delivery.py b/pype/modules/ftrack/actions/action_delivery.py index 8812ce9bc7..1beebe3e31 100644 --- a/pype/modules/ftrack/actions/action_delivery.py +++ b/pype/modules/ftrack/actions/action_delivery.py @@ -396,6 +396,13 @@ class Delivery(BaseAction): session.commit() self.db_con.uninstall() + if job["status"] == "failed": + return { + "success": False, + "message": "Delivery failed. Check logs for more information." + } + return True + def real_launch(self, session, entities, event): self.log.info("Delivery action just started.") report_items = collections.defaultdict(list) From 5fc00fa6f48b407e8a528abfb15637ff51b56a62 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Sat, 3 Oct 2020 01:15:19 +0200 Subject: [PATCH 086/279] renamed `load_json` to `load_json_file` --- pype/settings/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index b40e726ad1..e316b1697b 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -77,7 +77,7 @@ def default_settings(): return copy.deepcopy(_DEFAULT_SETTINGS) -def load_json(fpath): +def load_json_file(fpath): # Load json data with open(fpath, "r") as opened_file: lines = opened_file.read().splitlines() From effa7a28f8dedbe38ffb4c63a3bc72c53a2a246a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Sat, 3 Oct 2020 01:15:52 +0200 Subject: [PATCH 087/279] simplified `load_json_file` as jsons are expected to be saved with gui --- pype/settings/lib.py | 41 +---------------------------------------- 1 file changed, 1 insertion(+), 40 deletions(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index e316b1697b..953cbda0e6 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -79,48 +79,9 @@ def default_settings(): def load_json_file(fpath): # Load json data - with open(fpath, "r") as opened_file: - lines = opened_file.read().splitlines() - - # prepare json string - standard_json = "" - for line in lines: - # Remove all whitespace on both sides - line = line.strip() - - # Skip blank lines - if len(line) == 0: - continue - - standard_json += line - - # Check if has extra commas - extra_comma = False - if ",]" in standard_json or ",}" in standard_json: - extra_comma = True - standard_json = standard_json.replace(",]", "]") - standard_json = standard_json.replace(",}", "}") - - if extra_comma: - log.error("Extra comma in json file: \"{}\"".format(fpath)) - - # return empty dict if file is empty - if standard_json == "": - return {} - - # Try to parse string - try: - return json.loads(standard_json) - - except json.decoder.JSONDecodeError: - # Return empty dict if it is first time that decode error happened - return {} - - # Repreduce the exact same exception but traceback contains better - # information about position of error in the loaded json try: with open(fpath, "r") as opened_file: - json.load(opened_file) + return json.load(opened_file) except json.decoder.JSONDecodeError: log.warning( From d5b55f60b04eb2df6fa47afc1b065a9da27ba399 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Sat, 3 Oct 2020 01:16:41 +0200 Subject: [PATCH 088/279] changed `load_json` to `load_json_file` in code --- pype/settings/lib.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index 953cbda0e6..982ae07490 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -199,25 +199,25 @@ def load_jsons_from_dir(path, *args, **kwargs): def studio_system_settings(): if os.path.exists(SYSTEM_SETTINGS_PATH): - return load_json(SYSTEM_SETTINGS_PATH) + return load_json_file(SYSTEM_SETTINGS_PATH) return {} def studio_environments(): if os.path.exists(ENVIRONMENTS_PATH): - return load_json(ENVIRONMENTS_PATH) + return load_json_file(ENVIRONMENTS_PATH) return {} def studio_project_settings(): if os.path.exists(PROJECT_SETTINGS_PATH): - return load_json(PROJECT_SETTINGS_PATH) + return load_json_file(PROJECT_SETTINGS_PATH) return {} def studio_project_anatomy(): if os.path.exists(PROJECT_ANATOMY_PATH): - return load_json(PROJECT_ANATOMY_PATH) + return load_json_file(PROJECT_ANATOMY_PATH) return {} @@ -244,7 +244,7 @@ def project_settings_overrides(project_name): path_to_json = path_to_project_overrides(project_name) if not os.path.exists(path_to_json): return {} - return load_json(path_to_json) + return load_json_file(path_to_json) def project_anatomy_overrides(project_name): @@ -254,7 +254,7 @@ def project_anatomy_overrides(project_name): path_to_json = path_to_project_anatomy(project_name) if not os.path.exists(path_to_json): return {} - return load_json(path_to_json) + return load_json_file(path_to_json) def merge_overrides(global_dict, override_dict): From 8d23f491d2f52f7cd4f3a5fb964ac404f85ce72d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Sat, 3 Oct 2020 01:17:08 +0200 Subject: [PATCH 089/279] moved `load_jsons_from_dir` # Conflicts: # pype/settings/lib.py --- pype/settings/lib.py | 78 ++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index 982ae07490..de1aed31f6 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -92,7 +92,45 @@ def load_json_file(fpath): return {} -def find_environments(data, with_items=False, parents=None): +def load_jsons_from_dir(path, *args, **kwargs): + output = {} + + path = os.path.normpath(path) + if not os.path.exists(path): + # TODO warning + return output + + sub_keys = list(kwargs.pop("subkeys", args)) + for sub_key in tuple(sub_keys): + _path = os.path.join(path, sub_key) + if not os.path.exists(_path): + break + + path = _path + sub_keys.pop(0) + + base_len = len(path) + 1 + for base, _directories, filenames in os.walk(path): + base_items_str = base[base_len:] + if not base_items_str: + base_items = [] + else: + base_items = base_items_str.split(os.path.sep) + + for filename in filenames: + basename, ext = os.path.splitext(filename) + if ext == ".json": + full_path = os.path.join(base, filename) + value = load_json_file(full_path) + dict_keys = base_items + [basename] + output = subkey_merge(output, value, dict_keys) + + for sub_key in sub_keys: + output = output[sub_key] + return output + + +def find_environments(data): if not data or not isinstance(data, dict): return {} @@ -159,44 +197,6 @@ def subkey_merge(_dict, value, keys): return _dict -def load_jsons_from_dir(path, *args, **kwargs): - output = {} - - path = os.path.normpath(path) - if not os.path.exists(path): - # TODO warning - return output - - sub_keys = list(kwargs.pop("subkeys", args)) - for sub_key in tuple(sub_keys): - _path = os.path.join(path, sub_key) - if not os.path.exists(_path): - break - - path = _path - sub_keys.pop(0) - - base_len = len(path) + 1 - for base, _directories, filenames in os.walk(path): - base_items_str = base[base_len:] - if not base_items_str: - base_items = [] - else: - base_items = base_items_str.split(os.path.sep) - - for filename in filenames: - basename, ext = os.path.splitext(filename) - if ext == ".json": - full_path = os.path.join(base, filename) - value = load_json(full_path) - dict_keys = base_items + [basename] - output = subkey_merge(output, value, dict_keys) - - for sub_key in sub_keys: - output = output[sub_key] - return output - - def studio_system_settings(): if os.path.exists(SYSTEM_SETTINGS_PATH): return load_json_file(SYSTEM_SETTINGS_PATH) From 39d83c59ecd9629bf5a151c0949874c13d474f01 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Sat, 3 Oct 2020 01:19:17 +0200 Subject: [PATCH 090/279] path to project settings returns path to studio overrides if project name is None --- pype/settings/lib.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index de1aed31f6..a41b8fad8f 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -221,7 +221,9 @@ def studio_project_anatomy(): return {} -def path_to_project_overrides(project_name): +def path_to_project_settings(project_name): + if not project_name: + return PROJECT_SETTINGS_PATH return os.path.join( STUDIO_OVERRIDES_PATH, project_name, @@ -230,6 +232,8 @@ def path_to_project_overrides(project_name): def path_to_project_anatomy(project_name): + if not project_name: + return PROJECT_ANATOMY_PATH return os.path.join( STUDIO_OVERRIDES_PATH, project_name, @@ -241,7 +245,7 @@ def project_settings_overrides(project_name): if not project_name: return {} - path_to_json = path_to_project_overrides(project_name) + path_to_json = path_to_project_settings(project_name) if not os.path.exists(path_to_json): return {} return load_json_file(path_to_json) From 3697482fe15c83d097181ab1d5bc103cac08b9e5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Sat, 3 Oct 2020 01:19:36 +0200 Subject: [PATCH 091/279] added functions for saving settings --- pype/settings/lib.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index a41b8fad8f..783347a7b4 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -241,6 +241,38 @@ def path_to_project_anatomy(project_name): ) +def save_studio_settings(data): + dirpath = os.path.dirname(SYSTEM_SETTINGS_PATH) + if not os.path.exists(dirpath): + os.makedirs(dirpath) + + print("Saving studio overrides") + with open(SYSTEM_SETTINGS_PATH, "w") as file_stream: + json.dump(data, file_stream, indent=4) + + +def save_project_settings(project_name, overrides): + project_overrides_json_path = path_to_project_settings(project_name) + dirpath = os.path.dirname(project_overrides_json_path) + if not os.path.exists(dirpath): + os.makedirs(dirpath) + + print("Saving overrides of project \"{}\"".format(project_name)) + with open(project_overrides_json_path, "w") as file_stream: + json.dump(overrides, file_stream, indent=4) + + +def save_project_anatomy(project_name, anatomy_data): + project_anatomy_json_path = path_to_project_anatomy(project_name) + dirpath = os.path.dirname(project_anatomy_json_path) + if not os.path.exists(dirpath): + os.makedirs(dirpath) + + print("Saving anatomy of project \"{}\"".format(project_name)) + with open(project_anatomy_json_path, "w") as file_stream: + json.dump(anatomy_data, file_stream, indent=4) + + def project_settings_overrides(project_name): if not project_name: return {} From cdacc265721d43ed098dabc19f0b3895c06068cf Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Sat, 3 Oct 2020 01:19:44 +0200 Subject: [PATCH 092/279] STUDIO_OVERRIDES_PATH is safer --- pype/settings/lib.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index 783347a7b4..ab3e3fcbe6 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -13,7 +13,7 @@ M_ENVIRONMENT_KEY = "__environment_keys__" M_POP_KEY = "__pop_key__" # Folder where studio overrides are stored -STUDIO_OVERRIDES_PATH = os.environ["PYPE_PROJECT_CONFIGS"] +STUDIO_OVERRIDES_PATH = os.getenv("PYPE_PROJECT_CONFIGS") # File where studio's system overrides are stored SYSTEM_SETTINGS_KEY = "system_settings" @@ -88,7 +88,6 @@ def load_json_file(fpath): "File has invalid json format \"{}\"".format(fpath), exc_info=True ) - return {} From b9567b0fe1e1ed744d80dc5801f5f2ade74e1d20 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Sat, 3 Oct 2020 01:20:01 +0200 Subject: [PATCH 093/279] using saving functions in settings tool # Conflicts: # pype/tools/settings/settings/widgets/base.py --- pype/tools/settings/settings/widgets/base.py | 111 +++---------------- 1 file changed, 15 insertions(+), 96 deletions(-) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index 3f842602ca..19336b1ac3 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -4,11 +4,8 @@ import json from Qt import QtWidgets, QtCore, QtGui from pype.settings.lib import ( SYSTEM_SETTINGS_KEY, - SYSTEM_SETTINGS_PATH, PROJECT_SETTINGS_KEY, - PROJECT_SETTINGS_PATH, PROJECT_ANATOMY_KEY, - PROJECT_ANATOMY_PATH, DEFAULTS_DIR, @@ -22,12 +19,9 @@ from pype.settings.lib import ( project_settings_overrides, project_anatomy_overrides, - path_to_project_overrides, - path_to_project_anatomy, - - apply_overrides, - find_environments, - DuplicatedEnvGroups + save_studio_settings, + save_project_settings, + save_project_anatomy ) from .widgets import UnsavedChangesDialog from . import lib @@ -222,16 +216,7 @@ class SystemWidget(QtWidgets.QWidget): values = lib.convert_gui_data_to_overrides(_data.get("system", {})) - if not self.duplicated_env_group_validation(overrides=values): - return - - dirpath = os.path.dirname(SYSTEM_SETTINGS_PATH) - if not os.path.exists(dirpath): - os.makedirs(dirpath) - - print("Saving data to:", SYSTEM_SETTINGS_PATH) - with open(SYSTEM_SETTINGS_PATH, "w") as file_stream: - json.dump(values, file_stream, indent=4) + save_studio_settings(values) self._update_values() @@ -670,7 +655,7 @@ class ProjectWidget(QtWidgets.QWidget): has_invalid = True if not has_invalid: - return True + return self._save_overrides() invalid_items = [] for item in self.input_fields: @@ -688,16 +673,6 @@ class ProjectWidget(QtWidgets.QWidget): self.scroll_widget.ensureWidgetVisible(first_invalid_item) if first_invalid_item.isVisible(): first_invalid_item.setFocus(True) - return False - - def _save(self): - if not self.items_are_valid(): - return - - if self.project_name is None: - self._save_studio_overrides() - else: - self._save_overrides() def _on_refresh(self): self.reset() @@ -722,75 +697,19 @@ class ProjectWidget(QtWidgets.QWidget): ) # Saving overrides data - project_overrides_data = output_data.get( - PROJECT_SETTINGS_KEY, {} - ) - project_overrides_json_path = path_to_project_overrides( - self.project_name - ) - dirpath = os.path.dirname(project_overrides_json_path) - if not os.path.exists(dirpath): - os.makedirs(dirpath) - - print("Saving data to:", project_overrides_json_path) - with open(project_overrides_json_path, "w") as file_stream: - json.dump(project_overrides_data, file_stream, indent=4) + project_overrides_data = output_data.get(PROJECT_SETTINGS_KEY, {}) + save_project_settings(self.project_name, project_overrides_data) # Saving anatomy data - project_anatomy_data = output_data.get( - PROJECT_ANATOMY_KEY, {} - ) - project_anatomy_json_path = path_to_project_anatomy( - self.project_name - ) - dirpath = os.path.dirname(project_anatomy_json_path) - if not os.path.exists(dirpath): - os.makedirs(dirpath) + project_anatomy_data = output_data.get(PROJECT_ANATOMY_KEY, {}) + save_project_anatomy(self.project_name, project_anatomy_data) - print("Saving data to:", project_anatomy_json_path) - with open(project_anatomy_json_path, "w") as file_stream: - json.dump(project_anatomy_data, file_stream, indent=4) - - # Refill values with overrides - self._on_project_change() - - def _save_studio_overrides(self): - data = {} - for input_field in self.input_fields: - value, is_group = input_field.studio_overrides() - if value is not lib.NOT_SET: - data.update(value) - - output_data = lib.convert_gui_data_to_overrides( - data.get("project", {}) - ) - - # Project overrides data - project_overrides_data = output_data.get( - PROJECT_SETTINGS_KEY, {} - ) - dirpath = os.path.dirname(PROJECT_SETTINGS_PATH) - if not os.path.exists(dirpath): - os.makedirs(dirpath) - - print("Saving data to:", PROJECT_SETTINGS_PATH) - with open(PROJECT_SETTINGS_PATH, "w") as file_stream: - json.dump(project_overrides_data, file_stream, indent=4) - - # Project Anatomy data - project_anatomy_data = output_data.get( - PROJECT_ANATOMY_KEY, {} - ) - dirpath = os.path.dirname(PROJECT_ANATOMY_PATH) - if not os.path.exists(dirpath): - os.makedirs(dirpath) - - print("Saving data to:", PROJECT_ANATOMY_PATH) - with open(PROJECT_ANATOMY_PATH, "w") as file_stream: - json.dump(project_anatomy_data, file_stream, indent=4) - - # Update saved values - self._update_values() + if self.project_name: + # Refill values with overrides + self._on_project_change() + else: + # Update saved values + self._update_values() def _update_values(self): self.ignore_value_changes = True From 3a7cdae35cf5c1df18f68c345270693fef4fd6f5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Sat, 3 Oct 2020 01:31:02 +0200 Subject: [PATCH 094/279] make sure settings.lib import won't crash if PYPE_PROJECT_CONFIGS is not set --- pype/settings/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index ab3e3fcbe6..59820d6639 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -13,7 +13,7 @@ M_ENVIRONMENT_KEY = "__environment_keys__" M_POP_KEY = "__pop_key__" # Folder where studio overrides are stored -STUDIO_OVERRIDES_PATH = os.getenv("PYPE_PROJECT_CONFIGS") +STUDIO_OVERRIDES_PATH = os.getenv("PYPE_PROJECT_CONFIGS") or "" # File where studio's system overrides are stored SYSTEM_SETTINGS_KEY = "system_settings" From fa46b8afd7c5a99df8b5cf4d522ba7a2a29205f1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 5 Oct 2020 10:35:03 +0200 Subject: [PATCH 095/279] fixed saving of project settings # Conflicts: # pype/tools/settings/settings/widgets/base.py --- pype/tools/settings/settings/widgets/base.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index 19336b1ac3..c6db3c34de 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -687,8 +687,12 @@ class ProjectWidget(QtWidgets.QWidget): return data = {} + studio_overrides = bool(self.project_name is None) for item in self.input_fields: - value, _is_group = item.overrides() + if studio_overrides: + value, is_group = item.studio_overrides() + else: + value, is_group = item.overrides() if value is not lib.NOT_SET: data.update(value) @@ -714,7 +718,7 @@ class ProjectWidget(QtWidgets.QWidget): def _update_values(self): self.ignore_value_changes = True - default_values = default_values = lib.convert_data_to_gui_data( + default_values = lib.convert_data_to_gui_data( {"project": default_settings()} ) for input_field in self.input_fields: From e8e0261396a9b61dad0cd80769a12bec739deb44 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 5 Oct 2020 11:24:05 +0200 Subject: [PATCH 096/279] safer work with default settings --- pype/settings/lib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index 59820d6639..a998752287 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -324,13 +324,13 @@ def apply_overrides(source_data, override_data): def system_settings(): - default_values = default_settings()[SYSTEM_SETTINGS_KEY] + default_values = copy.deepcopy(default_settings()[SYSTEM_SETTINGS_KEY]) studio_values = studio_system_settings() return apply_overrides(default_values, studio_values) def project_settings(project_name): - default_values = default_settings()[PROJECT_SETTINGS_KEY] + default_values = copy.deepcopy(default_settings()[PROJECT_SETTINGS_KEY]) studio_values = studio_project_settings() studio_overrides = apply_overrides(default_values, studio_values) From 212bbbc8dffd6190ec1be2b2e921bd60874a79ee Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 5 Oct 2020 11:24:27 +0200 Subject: [PATCH 097/279] print more specific data --- pype/settings/lib.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index a998752287..c47710a4d1 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -245,7 +245,9 @@ def save_studio_settings(data): if not os.path.exists(dirpath): os.makedirs(dirpath) - print("Saving studio overrides") + print("Saving studio overrides. Output path: {}".format( + SYSTEM_SETTINGS_PATH + )) with open(SYSTEM_SETTINGS_PATH, "w") as file_stream: json.dump(data, file_stream, indent=4) @@ -256,7 +258,9 @@ def save_project_settings(project_name, overrides): if not os.path.exists(dirpath): os.makedirs(dirpath) - print("Saving overrides of project \"{}\"".format(project_name)) + print("Saving overrides of project \"{}\". Output path: {}".format( + project_name, project_overrides_json_path + )) with open(project_overrides_json_path, "w") as file_stream: json.dump(overrides, file_stream, indent=4) @@ -267,7 +271,9 @@ def save_project_anatomy(project_name, anatomy_data): if not os.path.exists(dirpath): os.makedirs(dirpath) - print("Saving anatomy of project \"{}\"".format(project_name)) + print("Saving anatomy of project \"{}\". Output path: {}".format( + project_name, project_anatomy_json_path + )) with open(project_anatomy_json_path, "w") as file_stream: json.dump(anatomy_data, file_stream, indent=4) From 4ae64993bcdb4d190971b00a94c2475c07b05dcf Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 5 Oct 2020 11:24:39 +0200 Subject: [PATCH 098/279] added few dostrings # Conflicts: # pype/settings/lib.py --- pype/settings/lib.py | 102 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 97 insertions(+), 5 deletions(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index c47710a4d1..5fbf5d11dd 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -92,6 +92,35 @@ def load_json_file(fpath): def load_jsons_from_dir(path, *args, **kwargs): + """Load all json files with content from entered path. + + Enterd path hiearchy: + |_ folder1 + | |_ data1.json + |_ folder2 + |_ subfolder1 + |_ data2.json + + Will result in: + ```javascript + { + "folder1": { + "data1": "CONTENT OF FILE" + }, + "folder2": { + "data1": { + "subfolder1": "CONTENT OF FILE" + } + } + } + ``` + + Args: + path (str): Path to folder where jsons should be. + + Returns: + dict: loaded data + """ output = {} path = os.path.normpath(path) @@ -130,6 +159,15 @@ def load_jsons_from_dir(path, *args, **kwargs): def find_environments(data): + """ Find environemnt values from system settings by it's metadata. + + Args: + data(dict): System settings data or dictionary which may contain + environments metadata. + + Returns: + dict: Key as Environment key and value for `acre` module. + """ if not data or not isinstance(data, dict): return {} @@ -197,24 +235,28 @@ def subkey_merge(_dict, value, keys): def studio_system_settings(): + """Studio overrides of system settings.""" if os.path.exists(SYSTEM_SETTINGS_PATH): return load_json_file(SYSTEM_SETTINGS_PATH) return {} def studio_environments(): + """Environment values from defaults.""" if os.path.exists(ENVIRONMENTS_PATH): return load_json_file(ENVIRONMENTS_PATH) return {} def studio_project_settings(): + """Studio overrides of default project settings.""" if os.path.exists(PROJECT_SETTINGS_PATH): return load_json_file(PROJECT_SETTINGS_PATH) return {} def studio_project_anatomy(): + """Studio overrides of default project anatomy data.""" if os.path.exists(PROJECT_ANATOMY_PATH): return load_json_file(PROJECT_ANATOMY_PATH) return {} @@ -241,6 +283,14 @@ def path_to_project_anatomy(project_name): def save_studio_settings(data): + """Save studio overrides of system settings. + + Saving must corespond with loading. For loading should be used function + `studio_system_settings`. + + Args: + data(dict): Data of studio overrides with override metadata. + """ dirpath = os.path.dirname(SYSTEM_SETTINGS_PATH) if not os.path.exists(dirpath): os.makedirs(dirpath) @@ -253,6 +303,17 @@ def save_studio_settings(data): def save_project_settings(project_name, overrides): + """Save studio overrides of project settings. + + Data are saved for specific project or as defaults for all projects. + Saving must corespond with loading. For loading should be used functions + `project_settings_overrides` and `studio_project_settings`. + + Args: + project_name(str, null): Project name for which overrides are + or None for global settings. + data(dict): Data of project overrides with override metadata. + """ project_overrides_json_path = path_to_project_settings(project_name) dirpath = os.path.dirname(project_overrides_json_path) if not os.path.exists(dirpath): @@ -266,6 +327,17 @@ def save_project_settings(project_name, overrides): def save_project_anatomy(project_name, anatomy_data): + """Save studio overrides of project anatomy. + + Data are saved for specific project or as defaults for all projects. + Saving must corespond with loading. For loading should be used functions + `project_anatomy_overrides` and `studio_project_anatomy`. + + Args: + project_name(str, null): Project name for which overrides are + or None for global settings. + data(dict): Data of project overrides with override metadata. + """ project_anatomy_json_path = path_to_project_anatomy(project_name) dirpath = os.path.dirname(project_anatomy_json_path) if not os.path.exists(dirpath): @@ -279,6 +351,14 @@ def save_project_anatomy(project_name, anatomy_data): def project_settings_overrides(project_name): + """Studio overrides of project settings for specific project. + + Args: + project_name(str): Name of project for which data should be loaded. + + Returns: + dict: Only overrides for entered project, may be empty dictionary. + """ if not project_name: return {} @@ -289,6 +369,14 @@ def project_settings_overrides(project_name): def project_anatomy_overrides(project_name): + """Studio overrides of project anatomy for specific project. + + Args: + project_name(str): Name of project for which data should be loaded. + + Returns: + dict: Only overrides for entered project, may be empty dictionary. + """ if not project_name: return {} @@ -299,6 +387,7 @@ def project_anatomy_overrides(project_name): def merge_overrides(global_dict, override_dict): + """Merge override data to source data by metadata stored in.""" if M_OVERRIDEN_KEY in override_dict: overriden_keys = set(override_dict.pop(M_OVERRIDEN_KEY)) else: @@ -308,10 +397,7 @@ def merge_overrides(global_dict, override_dict): if value == M_POP_KEY: global_dict.pop(key) - elif ( - key in overriden_keys - or key not in global_dict - ): + elif (key in overriden_keys or key not in global_dict): global_dict[key] = value elif isinstance(value, dict) and isinstance(global_dict[key], dict): @@ -330,12 +416,14 @@ def apply_overrides(source_data, override_data): def system_settings(): + """System settings with applied studio overrides.""" default_values = copy.deepcopy(default_settings()[SYSTEM_SETTINGS_KEY]) studio_values = studio_system_settings() return apply_overrides(default_values, studio_values) def project_settings(project_name): + """Project settings with applied studio and project overrides.""" default_values = copy.deepcopy(default_settings()[PROJECT_SETTINGS_KEY]) studio_values = studio_project_settings() @@ -347,7 +435,11 @@ def project_settings(project_name): def environments(): - # TODO remove these defaults (All should be set with system settings) + """Environments from defaults and extracted from system settings. + + Returns: + dict: Output should be ready for `acre` module. + """ envs = copy.deepcopy(default_settings()[ENVIRONMENTS_KEY]) # This is part of loading environments from settings envs_from_system_settings = find_environments(system_settings()) From 170d2dc305b7ba84eb5069a5a795e3bd73bbe387 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 5 Oct 2020 12:00:10 +0200 Subject: [PATCH 099/279] modified docstring in save functions to be more clear --- pype/settings/lib.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index 5fbf5d11dd..34603ef30e 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -285,8 +285,9 @@ def path_to_project_anatomy(project_name): def save_studio_settings(data): """Save studio overrides of system settings. - Saving must corespond with loading. For loading should be used function - `studio_system_settings`. + Do not use to store whole system settings data with defaults but only it's + overrides with metadata defining how overrides should be applied in load + function. For loading should be used function `studio_system_settings`. Args: data(dict): Data of studio overrides with override metadata. @@ -306,8 +307,12 @@ def save_project_settings(project_name, overrides): """Save studio overrides of project settings. Data are saved for specific project or as defaults for all projects. - Saving must corespond with loading. For loading should be used functions - `project_settings_overrides` and `studio_project_settings`. + + Do not use to store whole project settings data with defaults but only it's + overrides with metadata defining how overrides should be applied in load + function. For loading should be used functions `studio_project_settings` + for global project settings and `project_settings_overrides` for + project specific settings. Args: project_name(str, null): Project name for which overrides are @@ -329,9 +334,11 @@ def save_project_settings(project_name, overrides): def save_project_anatomy(project_name, anatomy_data): """Save studio overrides of project anatomy. - Data are saved for specific project or as defaults for all projects. - Saving must corespond with loading. For loading should be used functions - `project_anatomy_overrides` and `studio_project_anatomy`. + Do not use to store whole project anatomy data with defaults but only it's + overrides with metadata defining how overrides should be applied in load + function. For loading should be used functions `studio_project_anatomy` + for global project settings and `project_anatomy_overrides` for + project specific settings. Args: project_name(str, null): Project name for which overrides are From fd00cf196bea78a92ac734059de6fd839118ee32 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 5 Oct 2020 20:17:27 +0200 Subject: [PATCH 100/279] modified first docstring by comments --- pype/settings/lib.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index 34603ef30e..2614d55fbe 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -92,9 +92,12 @@ def load_json_file(fpath): def load_jsons_from_dir(path, *args, **kwargs): - """Load all json files with content from entered path. + """Load all .json files with content from entered folder path. - Enterd path hiearchy: + Data are loaded recursively from a directory and recreate the + hierarchy as a dictionary. + + Entered path hiearchy: |_ folder1 | |_ data1.json |_ folder2 @@ -116,10 +119,10 @@ def load_jsons_from_dir(path, *args, **kwargs): ``` Args: - path (str): Path to folder where jsons should be. + path (str): Path to the root folder where the json hierarchy starts. Returns: - dict: loaded data + dict: Loaded data. """ output = {} From cc9574981986235b2d787273aa2c9092a164a713 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Mon, 19 Oct 2020 13:27:48 +0200 Subject: [PATCH 101/279] Small fixes in docstrings --- pype/settings/lib.py | 42 +++++++++++++++--------------------------- 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index 2614d55fbe..adb5b2626f 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -23,9 +23,6 @@ SYSTEM_SETTINGS_PATH = os.path.join( # File where studio's environment overrides are stored ENVIRONMENTS_KEY = "environments" -ENVIRONMENTS_PATH = os.path.join( - STUDIO_OVERRIDES_PATH, ENVIRONMENTS_KEY + ".json" -) # File where studio's default project overrides are stored PROJECT_SETTINGS_KEY = "project_settings" @@ -244,13 +241,6 @@ def studio_system_settings(): return {} -def studio_environments(): - """Environment values from defaults.""" - if os.path.exists(ENVIRONMENTS_PATH): - return load_json_file(ENVIRONMENTS_PATH) - return {} - - def studio_project_settings(): """Studio overrides of default project settings.""" if os.path.exists(PROJECT_SETTINGS_PATH): @@ -335,13 +325,7 @@ def save_project_settings(project_name, overrides): def save_project_anatomy(project_name, anatomy_data): - """Save studio overrides of project anatomy. - - Do not use to store whole project anatomy data with defaults but only it's - overrides with metadata defining how overrides should be applied in load - function. For loading should be used functions `studio_project_anatomy` - for global project settings and `project_anatomy_overrides` for - project specific settings. + """Save studio overrides of project anatomy data. Args: project_name(str, null): Project name for which overrides are @@ -396,8 +380,9 @@ def project_anatomy_overrides(project_name): return load_json_file(path_to_json) -def merge_overrides(global_dict, override_dict): - """Merge override data to source data by metadata stored in.""" +def merge_overrides(source_dict, override_dict): + """Merge data from override_dict to source_dict.""" + if M_OVERRIDEN_KEY in override_dict: overriden_keys = set(override_dict.pop(M_OVERRIDEN_KEY)) else: @@ -405,17 +390,17 @@ def merge_overrides(global_dict, override_dict): for key, value in override_dict.items(): if value == M_POP_KEY: - global_dict.pop(key) + source_dict.pop(key) - elif (key in overriden_keys or key not in global_dict): - global_dict[key] = value + elif (key in overriden_keys or key not in source_dict): + source_dict[key] = value - elif isinstance(value, dict) and isinstance(global_dict[key], dict): - global_dict[key] = merge_overrides(global_dict[key], value) + elif isinstance(value, dict) and isinstance(source_dict[key], dict): + source_dict[key] = merge_overrides(source_dict[key], value) else: - global_dict[key] = value - return global_dict + source_dict[key] = value + return source_dict def apply_overrides(source_data, override_data): @@ -445,7 +430,10 @@ def project_settings(project_name): def environments(): - """Environments from defaults and extracted from system settings. + """Calculated environment based on defaults and system settings. + + Any default environment also found in the system settings will be fully + overriden by the one from the system settings. Returns: dict: Output should be ready for `acre` module. From 0ebd6466e90ee138a2c5386e49a65951e0ebe6ae Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 03:32:30 +0100 Subject: [PATCH 102/279] updated lib with new modifications --- pype/settings/lib.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index adb5b2626f..a50d7793b5 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -158,7 +158,7 @@ def load_jsons_from_dir(path, *args, **kwargs): return output -def find_environments(data): +def find_environments(data, with_items=False, parents=None): """ Find environemnt values from system settings by it's metadata. Args: @@ -412,14 +412,14 @@ def apply_overrides(source_data, override_data): def system_settings(): """System settings with applied studio overrides.""" - default_values = copy.deepcopy(default_settings()[SYSTEM_SETTINGS_KEY]) + default_values = default_settings()[SYSTEM_SETTINGS_KEY] studio_values = studio_system_settings() return apply_overrides(default_values, studio_values) def project_settings(project_name): """Project settings with applied studio and project overrides.""" - default_values = copy.deepcopy(default_settings()[PROJECT_SETTINGS_KEY]) + default_values = default_settings()[PROJECT_SETTINGS_KEY] studio_values = studio_project_settings() studio_overrides = apply_overrides(default_values, studio_values) @@ -438,6 +438,7 @@ def environments(): Returns: dict: Output should be ready for `acre` module. """ + # TODO remove these defaults (All should be set with system settings) envs = copy.deepcopy(default_settings()[ENVIRONMENTS_KEY]) # This is part of loading environments from settings envs_from_system_settings = find_environments(system_settings()) From b873c9bc8221fe368cc46eda0865387f58f86d34 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 03:33:49 +0100 Subject: [PATCH 103/279] updated base with new changes --- pype/tools/settings/settings/widgets/base.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index c6db3c34de..3e1c6ea6b9 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -21,7 +21,11 @@ from pype.settings.lib import ( save_studio_settings, save_project_settings, - save_project_anatomy + save_project_anatomy, + + apply_overrides, + find_environments, + DuplicatedEnvGroups ) from .widgets import UnsavedChangesDialog from . import lib @@ -216,6 +220,9 @@ class SystemWidget(QtWidgets.QWidget): values = lib.convert_gui_data_to_overrides(_data.get("system", {})) + if not self.duplicated_env_group_validation(overrides=values): + return + save_studio_settings(values) self._update_values() @@ -528,7 +535,7 @@ class ProjectWidget(QtWidgets.QWidget): layout.addWidget(project_list_widget, 0) layout.addWidget(configurations_widget, 1) - save_btn.clicked.connect(self._save) + save_btn.clicked.connect(self._save_overrides) project_list_widget.project_changed.connect(self._on_project_change) self.project_list_widget = project_list_widget @@ -655,7 +662,7 @@ class ProjectWidget(QtWidgets.QWidget): has_invalid = True if not has_invalid: - return self._save_overrides() + return True invalid_items = [] for item in self.input_fields: @@ -673,6 +680,7 @@ class ProjectWidget(QtWidgets.QWidget): self.scroll_widget.ensureWidgetVisible(first_invalid_item) if first_invalid_item.isVisible(): first_invalid_item.setFocus(True) + return False def _on_refresh(self): self.reset() From f20c8d142ea953abe492f11fd7438b1cabb9d29e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 03:43:34 +0100 Subject: [PATCH 104/279] fixed refresh of project widgets --- pype/tools/settings/settings/widgets/base.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index 3e1c6ea6b9..653da51d43 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -563,11 +563,11 @@ class ProjectWidget(QtWidgets.QWidget): input_field.hierarchical_style_update() def reset(self): - if self.content_layout.count() != 0: - for widget in self.input_fields: - self.content_layout.removeWidget(widget) - widget.deleteLater() - self.input_fields.clear() + self.input_fields.clear() + while self.content_layout.count() != 0: + widget = self.content_layout.itemAt(0).widget() + self.content_layout.removeWidget(widget) + widget.deleteLater() self.schema = lib.gui_schema("projects_schema", "0_project_gui_schema") self.keys = self.schema.get("keys", []) From 154005006878941378bd18a8492dc72317f95276 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 11:23:11 +0100 Subject: [PATCH 105/279] modified `initial_attributes` renamed variable `input_data` to `schema_data` which are stored to item also "key" is required key --- .../settings/settings/widgets/item_types.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 472a5b111c..eacfb94046 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -134,7 +134,7 @@ class SettingObject: role_name = self.user_role return role_name in self._roles - def initial_attributes(self, input_data, parent, as_widget): + def initial_attributes(self, schema_data, parent, as_widget): """Prepare attributes based on entered arguments. This method should be same for each item type. Few item types @@ -142,23 +142,25 @@ class SettingObject: """ self._set_default_attributes() + self.schema_data = schema_data + self._parent = parent self._as_widget = as_widget - self._roles = input_data.get("roles") + self._roles = schema_data.get("roles") if self._roles is not None and not isinstance(self._roles, list): self._roles = [self._roles] - self._is_group = input_data.get("is_group", False) - self._env_group_key = input_data.get("env_group_key") + self._is_group = schema_data.get("is_group", False) + self._env_group_key = schema_data.get("env_group_key") # TODO not implemented yet - self._is_nullable = input_data.get("is_nullable", False) + self._is_nullable = schema_data.get("is_nullable", False) if self.is_environ: if not self.allow_to_environment: raise TypeError(( "Item {} does not allow to store environment values" - ).format(input_data["type"])) + ).format(schema_data["type"])) self.add_environ_field(self) @@ -178,6 +180,9 @@ class SettingObject: self.hide() self.hidden_by_role = True + if not self.as_widget: + self.key = self.schema_data["key"] + @property def user_role(self): """Tool is running with any user role. From 76bfb6a578ff1a8e0e2389e84cc328241a170260 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 11:31:50 +0100 Subject: [PATCH 106/279] split items creation to initialization in `__init__` and `create_ui` methods --- .../settings/widgets/anatomy_types.py | 18 +- pype/tools/settings/settings/widgets/base.py | 2 + .../settings/settings/widgets/item_types.py | 307 +++++++++--------- 3 files changed, 160 insertions(+), 167 deletions(-) diff --git a/pype/tools/settings/settings/widgets/anatomy_types.py b/pype/tools/settings/settings/widgets/anatomy_types.py index e1a726187c..3eb2bc0d3e 100644 --- a/pype/tools/settings/settings/widgets/anatomy_types.py +++ b/pype/tools/settings/settings/widgets/anatomy_types.py @@ -34,7 +34,7 @@ class AnatomyWidget(QtWidgets.QWidget, SettingObject): } def __init__( - self, input_data, parent, as_widget=False, label_widget=None + self, schema_data, parent, as_widget=False ): if as_widget: raise TypeError( @@ -43,11 +43,12 @@ class AnatomyWidget(QtWidgets.QWidget, SettingObject): super(AnatomyWidget, self).__init__(parent) self.setObjectName("AnatomyWidget") - self.initial_attributes(input_data, parent, as_widget) + self.initial_attributes(schema_data, parent, as_widget) - self.key = input_data["key"] + self.key = schema_data["key"] - children_data = input_data["children"] + def create_ui(self, label_widget=None): + children_data = self.schema_data["children"] roots_input_data = {} templates_input_data = {} for child in children_data: @@ -269,6 +270,7 @@ class RootsWidget(QtWidgets.QWidget, SettingObject): path_widget_data, self, as_widget=True, parent_widget=content_widget ) + singleroot_widget.create_ui() multiroot_data = { "key": self.key, "expandable": False, @@ -281,6 +283,7 @@ class RootsWidget(QtWidgets.QWidget, SettingObject): multiroot_data, self, as_widget=True, parent_widget=content_widget ) + multiroot_widget.create_ui() content_layout = QtWidgets.QVBoxLayout(content_widget) content_layout.setContentsMargins(0, 0, 0, 0) @@ -638,10 +641,9 @@ class TemplatesWidget(QtWidgets.QWidget, SettingObject): } self.body_widget = body_widget self.label_widget = body_widget.label_widget - self.value_input = RawJsonWidget( - template_input_data, self, - label_widget=self.label_widget - ) + self.value_input = RawJsonWidget(template_input_data, self) + self.value_input.create_ui(label_widget=self.label_widget) + content_layout.addWidget(self.value_input) layout = QtWidgets.QVBoxLayout(self) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index 3f842602ca..ff35dc254c 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -321,6 +321,7 @@ class SystemWidget(QtWidgets.QWidget): item_type = child_configuration["type"] klass = lib.TypeToKlass.types.get(item_type) item = klass(child_configuration, self) + item.create_ui() self.input_fields.append(item) self.content_layout.addWidget(item, 0) @@ -587,6 +588,7 @@ class ProjectWidget(QtWidgets.QWidget): item_type = child_configuration["type"] klass = lib.TypeToKlass.types.get(item_type) item = klass(child_configuration, self) + item.create_ui() self.input_fields.append(item) self.content_layout.addWidget(item, 0) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index eacfb94046..387398a32b 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -916,7 +916,7 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): def __init__( self, input_data, parent, - as_widget=False, label_widget=None, parent_widget=None + as_widget=False, parent_widget=None ): if parent_widget is None: parent_widget = parent @@ -924,17 +924,16 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): self.initial_attributes(input_data, parent, as_widget) + def create_ui(self, label_widget=None): layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - if not self.as_widget: - self.key = input_data["key"] - if not label_widget: - label = input_data["label"] - label_widget = QtWidgets.QLabel(label) - label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) - layout.addWidget(label_widget, 0) + if not self.as_widget and not label_widget: + label = self.schema_data["label"] + label_widget = QtWidgets.QLabel(label) + label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + layout.addWidget(label_widget, 0) self.label_widget = label_widget checkbox_height = self.style().pixelMetric( @@ -969,34 +968,32 @@ class NumberWidget(QtWidgets.QWidget, InputObject): valid_value_types = (int, float) def __init__( - self, input_data, parent, - as_widget=False, label_widget=None, parent_widget=None + self, schema_data, parent, as_widget=False, parent_widget=None ): if parent_widget is None: parent_widget = parent super(NumberWidget, self).__init__(parent_widget) - self.initial_attributes(input_data, parent, as_widget) + self.initial_attributes(schema_data, parent, as_widget) + def create_ui(self, label_widget=None): layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) kwargs = { - modifier: input_data.get(modifier) + modifier: self.schema_data.get(modifier) for modifier in self.input_modifiers - if input_data.get(modifier) + if self.schema_data.get(modifier) } self.input_field = NumberSpinBox(self, **kwargs) self.setFocusProxy(self.input_field) - if not self._as_widget: - self.key = input_data["key"] - if not label_widget: - label = input_data["label"] - label_widget = QtWidgets.QLabel(label) - layout.addWidget(label_widget, 0) + if not self._as_widget and not label_widget: + label = self.schema_data["label"] + label_widget = QtWidgets.QLabel(label) + layout.addWidget(label_widget, 0) self.label_widget = label_widget layout.addWidget(self.input_field, 1) @@ -1017,17 +1014,17 @@ class TextWidget(QtWidgets.QWidget, InputObject): valid_value_types = (str, ) def __init__( - self, input_data, parent, - as_widget=False, label_widget=None, parent_widget=None + self, schema_data, parent, as_widget=False, parent_widget=None ): if parent_widget is None: parent_widget = parent super(TextWidget, self).__init__(parent_widget) - self.initial_attributes(input_data, parent, as_widget) - self.multiline = input_data.get("multiline", False) - placeholder = input_data.get("placeholder") + self.initial_attributes(schema_data, parent, as_widget) + self.multiline = schema_data.get("multiline", False) + self.placeholder_text = schema_data.get("placeholder") + def create_ui(self, label_widget=None): layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) @@ -1037,8 +1034,8 @@ class TextWidget(QtWidgets.QWidget, InputObject): else: self.input_field = QtWidgets.QLineEdit(self) - if placeholder: - self.input_field.setPlaceholderText(placeholder) + if self.placeholder_text: + self.input_field.setPlaceholderText(self.placeholder_text) self.setFocusProxy(self.input_field) @@ -1046,12 +1043,10 @@ class TextWidget(QtWidgets.QWidget, InputObject): if self.multiline: layout_kwargs["alignment"] = QtCore.Qt.AlignTop - if not self._as_widget: - self.key = input_data["key"] - if not label_widget: - label = input_data["label"] - label_widget = QtWidgets.QLabel(label) - layout.addWidget(label_widget, 0, **layout_kwargs) + if not self._as_widget and not label_widget: + label = self.schema_data["label"] + label_widget = QtWidgets.QLabel(label) + layout.addWidget(label_widget, 0, **layout_kwargs) self.label_widget = label_widget layout.addWidget(self.input_field, 1, **layout_kwargs) @@ -1078,25 +1073,23 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): valid_value_types = (str, ) def __init__( - self, input_data, parent, - as_widget=False, label_widget=None, parent_widget=None + self, schema_data, parent, as_widget=False, parent_widget=None ): if parent_widget is None: parent_widget = parent super(PathInputWidget, self).__init__(parent_widget) - self.initial_attributes(input_data, parent, as_widget) + self.initial_attributes(schema_data, parent, as_widget) + def create_ui(self, label_widget=None): layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - if not self._as_widget: - self.key = input_data["key"] - if not label_widget: - label = input_data["label"] - label_widget = QtWidgets.QLabel(label) - layout.addWidget(label_widget, 0) + if not self._as_widget and not label_widget: + label = self.schema_data["label"] + label_widget = QtWidgets.QLabel(label) + layout.addWidget(label_widget, 0) self.label_widget = label_widget self.input_field = PathInput(self) @@ -1122,34 +1115,32 @@ class EnumeratorWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( - self, input_data, parent, - as_widget=False, label_widget=None, parent_widget=None + self, schema_data, parent, as_widget=False, parent_widget=None ): if parent_widget is None: parent_widget = parent super(EnumeratorWidget, self).__init__(parent_widget) - self.initial_attributes(input_data, parent, as_widget) - self.multiselection = input_data.get("multiselection") - self.enum_items = input_data["enum_items"] + self.initial_attributes(schema_data, parent, as_widget) + self.multiselection = schema_data.get("multiselection") + self.enum_items = schema_data["enum_items"] if not self.enum_items: raise ValueError("Attribute `enum_items` is not defined.") + def create_ui(self, label_widget=None): layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - if not self._as_widget: - self.key = input_data["key"] - if not label_widget: - label = input_data["label"] - label_widget = QtWidgets.QLabel(label) - label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) - layout.addWidget(label_widget, 0) + if not self._as_widget and not label_widget: + label = self.schema_data["label"] + label_widget = QtWidgets.QLabel(label) + label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + layout.addWidget(label_widget, 0) self.label_widget = label_widget if self.multiselection: - placeholder = input_data.get("placeholder") + placeholder = self.schema_data.get("placeholder") self.input_field = MultiSelectionComboBox( placeholder=placeholder, parent=self ) @@ -1276,15 +1267,17 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): allow_to_environment = True def __init__( - self, input_data, parent, - as_widget=False, label_widget=None, parent_widget=None + self, schema_data, parent, as_widget=False, parent_widget=None ): if parent_widget is None: parent_widget = parent super(RawJsonWidget, self).__init__(parent_widget) - self.initial_attributes(input_data, parent, as_widget) + self.initial_attributes(schema_data, parent, as_widget) + # By default must be invalid + self._is_invalid = True + def create_ui(self, label_widget=None): layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) @@ -1294,16 +1287,13 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.MinimumExpanding ) - self._is_invalid = self.input_field.has_invalid_value() self.setFocusProxy(self.input_field) - if not self.as_widget: - self.key = input_data["key"] - if not label_widget: - label = input_data["label"] - label_widget = QtWidgets.QLabel(label) - layout.addWidget(label_widget, 0, alignment=QtCore.Qt.AlignTop) + if not self.as_widget and not label_widget: + label = self.schema_data["label"] + label_widget = QtWidgets.QLabel(label) + layout.addWidget(label_widget, 0, alignment=QtCore.Qt.AlignTop) self.label_widget = label_widget layout.addWidget(self.input_field, 1, alignment=QtCore.Qt.AlignTop) @@ -1408,9 +1398,9 @@ class ListItem(QtWidgets.QWidget, SettingObject): self.value_input = ItemKlass( item_schema, self, - as_widget=True, - label_widget=None + as_widget=True ) + self.value_input.create_ui() layout.addWidget(self.value_input, 1) @@ -1540,17 +1530,18 @@ class ListWidget(QtWidgets.QWidget, InputObject): valid_value_types = (list, ) def __init__( - self, input_data, parent, - as_widget=False, label_widget=None, parent_widget=None + self, schema_data, parent, as_widget=False, parent_widget=None ): if parent_widget is None: parent_widget = parent super(ListWidget, self).__init__(parent_widget) self.setObjectName("ListWidget") - self.initial_attributes(input_data, parent, as_widget) + self.initial_attributes(schema_data, parent, as_widget) - object_type = input_data["object_type"] + self.input_fields = [] + + object_type = schema_data["object_type"] if isinstance(object_type, dict): self.item_schema = object_type else: @@ -1558,7 +1549,7 @@ class ListWidget(QtWidgets.QWidget, InputObject): "type": object_type } # Backwards compatibility - input_modifiers = input_data.get("input_modifiers") or {} + input_modifiers = schema_data.get("input_modifiers") or {} if input_modifiers: self.log.warning(( "Used deprecated key `input_modifiers` to define item." @@ -1566,17 +1557,14 @@ class ListWidget(QtWidgets.QWidget, InputObject): )) self.item_schema.update(input_modifiers) - self.input_fields = [] - + def create_ui(self, label_widget=None): layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 5) layout.setSpacing(5) - if not self.as_widget: - self.key = input_data["key"] - if not label_widget: - label_widget = QtWidgets.QLabel(input_data["label"], self) - layout.addWidget(label_widget, alignment=QtCore.Qt.AlignTop) + if not self.as_widget and not label_widget: + label_widget = QtWidgets.QLabel(self.schema_data["label"], self) + layout.addWidget(label_widget, alignment=QtCore.Qt.AlignTop) self.label_widget = label_widget @@ -1788,39 +1776,39 @@ class ListStrictWidget(QtWidgets.QWidget, InputObject): valid_value_types = (list, ) def __init__( - self, input_data, parent, - as_widget=False, label_widget=None, parent_widget=None + self, schema_data, parent, as_widget=False, parent_widget=None ): if parent_widget is None: parent_widget = parent super(ListStrictWidget, self).__init__(parent_widget) self.setObjectName("ListStrictWidget") - self.initial_attributes(input_data, parent, as_widget) + self.initial_attributes(schema_data, parent, as_widget) + + self.is_horizontal = schema_data.get("horizontal", True) + self.object_types = self.schema_data["object_types"] self.input_fields = [] + def create_ui(self, label_widget=None): layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 5) layout.setSpacing(5) - if not self.as_widget: - self.key = input_data["key"] - if not label_widget: - label_widget = QtWidgets.QLabel(input_data["label"], self) - layout.addWidget(label_widget, alignment=QtCore.Qt.AlignTop) + if not self.as_widget and not label_widget: + label_widget = QtWidgets.QLabel(self.schema_data["label"], self) + layout.addWidget(label_widget, alignment=QtCore.Qt.AlignTop) self.label_widget = label_widget - self._add_children(layout, input_data) + self._add_children(layout) - def _add_children(self, layout, input_data): + def _add_children(self, layout): inputs_widget = QtWidgets.QWidget(self) inputs_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) layout.addWidget(inputs_widget) - horizontal = input_data.get("horizontal", True) - if horizontal: + if self.is_horizontal: inputs_layout = QtWidgets.QHBoxLayout(inputs_widget) else: inputs_layout = QtWidgets.QGridLayout(inputs_widget) @@ -1832,7 +1820,7 @@ class ListStrictWidget(QtWidgets.QWidget, InputObject): self.inputs_layout = inputs_layout children_item_mapping = [] - for child_configuration in input_data["object_types"]: + for child_configuration in self.object_types: item_widget = ListItem( child_configuration, self, self.inputs_widget, is_strict=True ) @@ -1847,7 +1835,7 @@ class ListStrictWidget(QtWidgets.QWidget, InputObject): children_item_mapping.append((label_widget, item_widget)) - if horizontal: + if self.is_horizontal: self._add_children_horizontally(children_item_mapping) else: self._add_children_vertically(children_item_mapping) @@ -1977,9 +1965,10 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self.value_input = ItemKlass( item_schema, self, - as_widget=True, - label_widget=None + as_widget=True ) + self.value_input.create_ui() + self.add_btn = QtWidgets.QPushButton("+") self.remove_btn = QtWidgets.QPushButton("-") @@ -2138,22 +2127,25 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): valid_value_types = (dict, ) def __init__( - self, input_data, parent, - as_widget=False, label_widget=None, parent_widget=None + self, schema_data, parent, as_widget=False, parent_widget=None ): if parent_widget is None: parent_widget = parent super(ModifiableDict, self).__init__(parent_widget) self.setObjectName("ModifiableDict") - self.initial_attributes(input_data, parent, as_widget) + self.initial_attributes(schema_data, parent, as_widget) self.input_fields = [] - self.key = input_data["key"] - self.value_is_env_group = input_data.get("value_is_env_group") or False + # Validation of "key" key + self.key = schema_data["key"] + self.value_is_env_group = ( + schema_data.get("value_is_env_group") or False + ) + self.hightlight_content = self.schema_data.get("highlight_content") - object_type = input_data["object_type"] + object_type = schema_data["object_type"] if isinstance(object_type, dict): self.item_schema = object_type else: @@ -2161,7 +2153,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.item_schema = { "type": object_type } - input_modifiers = input_data.get("input_modifiers") or {} + input_modifiers = schema_data.get("input_modifiers") or {} if input_modifiers: self.log.warning(( "Used deprecated key `input_modifiers` to define item." @@ -2172,7 +2164,8 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): if self.value_is_env_group: self.item_schema["env_group_key"] = "" - if input_data.get("highlight_content", False): + def create_ui(self, label_widget=None): + if self.hightlight_content: content_state = "hightlighted" bottom_margin = 5 else: @@ -2183,9 +2176,9 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): main_layout.setContentsMargins(0, 0, 0, 0) main_layout.setSpacing(0) - label = input_data.get("label") + label = self.schema_data.get("label") - if as_widget: + if self.as_widget: body_widget = None self.label_widget = label_widget @@ -2193,7 +2186,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): body_widget = None self.label_widget = None else: - body_widget = ExpandingWidget(input_data["label"], self) + body_widget = ExpandingWidget(self.schema_data["label"], self) main_layout.addWidget(body_widget) self.label_widget = body_widget.label_widget @@ -2221,9 +2214,9 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.content_layout = content_layout if body_widget: - collapsable = input_data.get("collapsable", True) + collapsable = self.schema_data.get("collapsable", True) if collapsable: - collapsed = input_data.get("collapsed", True) + collapsed = self.schema_data.get("collapsed", True) if not collapsed: body_widget.toggle_content() @@ -2416,29 +2409,31 @@ class DictWidget(QtWidgets.QWidget, SettingObject): valid_value_types = (dict, type(NOT_SET)) def __init__( - self, input_data, parent, - as_widget=False, label_widget=None, parent_widget=None + self, schema_data, parent, as_widget=False, parent_widget=None ): if parent_widget is None: parent_widget = parent super(DictWidget, self).__init__(parent_widget) - self.initial_attributes(input_data, parent, as_widget) + self.initial_attributes(schema_data, parent, as_widget) self.input_fields = [] self.checkbox_widget = None - self.checkbox_key = input_data.get("checkbox_key") + self.checkbox_key = schema_data.get("checkbox_key") - if not self.as_widget: - self.key = input_data["key"] + self.highlight_content = schema_data.get("highlight_content", False) + self.show_borders = schema_data.get("show_borders", True) + self.collapsable = schema_data.get("collapsable", True) + self.collapsed = schema_data.get("collapsed", True) - if not self.as_widget and input_data.get("label") is None: + def create_ui(self, label_widget=None): + if not self.as_widget and self.schema_data.get("label") is None: self._ui_item_without_label() else: - self._ui_item_or_as_widget(input_data, label_widget) + self._ui_item_or_as_widget(label_widget) - for child_data in input_data.get("children", []): + for child_data in self.schema_data.get("children", []): self.add_children_gui(child_data) any_visible = False @@ -2464,14 +2459,12 @@ class DictWidget(QtWidgets.QWidget, SettingObject): self.content_layout.setContentsMargins(0, 0, 0, 0) self.content_layout.setSpacing(5) - def _ui_item_or_as_widget(self, input_data, label_widget): + def _ui_item_or_as_widget(self, label_widget): content_widget = QtWidgets.QWidget(self) if self.as_widget: content_widget.setObjectName("DictAsWidgetBody") - show_borders = str( - int(input_data.get("show_borders", True)) - ) + show_borders = str(int(self.show_borders)) content_widget.setProperty("show_borders", show_borders) content_layout_margins = (5, 5, 5, 5) main_layout_spacing = 5 @@ -2479,7 +2472,7 @@ class DictWidget(QtWidgets.QWidget, SettingObject): else: content_widget.setObjectName("ContentWidget") - if input_data.get("highlight_content", False): + if self.highlight_content: content_state = "hightlighted" bottom_margin = 5 else: @@ -2489,7 +2482,7 @@ class DictWidget(QtWidgets.QWidget, SettingObject): content_layout_margins = (CHILD_OFFSET, 5, 0, bottom_margin) main_layout_spacing = 0 - body_widget = ExpandingWidget(input_data["label"], self) + body_widget = ExpandingWidget(self.schema_data["label"], self) label_widget = body_widget.label_widget body_widget.set_content_widget(content_widget) @@ -2509,13 +2502,11 @@ class DictWidget(QtWidgets.QWidget, SettingObject): self.content_layout = content_layout if body_widget: - collapsable = input_data.get("collapsable", True) if len(self.input_fields) == 1 and self.checkbox_widget: body_widget.hide_toolbox(hide_content=True) - elif collapsable: - collapsed = input_data.get("collapsed", True) - if not collapsed: + elif self.collapsable: + if not self.collapsed: body_widget.toggle_content() else: body_widget.hide_toolbox(hide_content=False) @@ -2547,13 +2538,14 @@ class DictWidget(QtWidgets.QWidget, SettingObject): return self._add_checkbox_child(child_configuration) label_widget = None - if not klass.expand_in_grid: + item = klass(child_configuration, self) + if not item.expand_in_grid: label = child_configuration.get("label") if label is not None: label_widget = GridLabelWidget(label, self) self.content_layout.addWidget(label_widget, row, 0, 1, 1) - item = klass(child_configuration, self, label_widget=label_widget) + item.create_ui(label_widget=label_widget) item.value_changed.connect(self._on_value_change) if label_widget: @@ -2569,8 +2561,9 @@ class DictWidget(QtWidgets.QWidget, SettingObject): def _add_checkbox_child(self, child_configuration): item = BooleanWidget( - child_configuration, self, label_widget=self.label_widget + child_configuration, self ) + item.create_ui(label_widget=self.label_widget) item.value_changed.connect(self._on_value_change) self.body_widget.add_widget_before_label(item) @@ -2872,14 +2865,13 @@ class PathWidget(QtWidgets.QWidget, SettingObject): } def __init__( - self, input_data, parent, - as_widget=False, label_widget=None, parent_widget=None + self, schema_data, parent, as_widget=False, parent_widget=None ): if parent_widget is None: parent_widget = parent super(PathWidget, self).__init__(parent_widget) - self.initial_attributes(input_data, parent, as_widget) + self.initial_attributes(schema_data, parent, as_widget) # This is partial input and dictionary input if not self.any_parent_is_group and not self._as_widget: @@ -2887,22 +2879,20 @@ class PathWidget(QtWidgets.QWidget, SettingObject): else: self._is_group = False - self.multiplatform = input_data.get("multiplatform", False) - self.multipath = input_data.get("multipath", False) + self.multiplatform = schema_data.get("multiplatform", False) + self.multipath = schema_data.get("multipath", False) self.input_field = None + def create_ui(self, label_widget=None): layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - if not self.as_widget: - self.key = input_data["key"] - if not label_widget: - label = input_data["label"] - label_widget = QtWidgets.QLabel(label) - label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) - layout.addWidget(label_widget, 0, alignment=QtCore.Qt.AlignTop) + if not self.as_widget and not label_widget: + label_widget = QtWidgets.QLabel(self.schema_data["label"]) + label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + layout.addWidget(label_widget, 0, alignment=QtCore.Qt.AlignTop) self.label_widget = label_widget self.content_widget = QtWidgets.QWidget(self) @@ -2912,7 +2902,7 @@ class PathWidget(QtWidgets.QWidget, SettingObject): layout.addWidget(self.content_widget) - self.create_gui() + self.create_ui_inputs() @property def default_input_value(self): @@ -2928,13 +2918,12 @@ class PathWidget(QtWidgets.QWidget, SettingObject): } return value_type() - def create_gui(self): + def create_ui_inputs(self): if not self.multiplatform and not self.multipath: input_data = {"key": self.key} - path_input = PathInputWidget( - input_data, self, - as_widget=True, label_widget=self.label_widget - ) + path_input = PathInputWidget(input_data, self, as_widget=True) + path_input.create_ui(label_widget=self.label_widget) + self.setFocusProxy(path_input) self.content_layout.addWidget(path_input) self.input_field = path_input @@ -2946,10 +2935,8 @@ class PathWidget(QtWidgets.QWidget, SettingObject): "key": self.key, "object_type": "path-input" } - input_widget = ListWidget( - item_schema, self, - as_widget=True, label_widget=self.label_widget - ) + input_widget = ListWidget(item_schema, self, as_widget=True) + input_widget.create_ui(label_widget=self.label_widget) self.setFocusProxy(input_widget) self.content_layout.addWidget(input_widget) self.input_field = input_widget @@ -2975,9 +2962,9 @@ class PathWidget(QtWidgets.QWidget, SettingObject): item_schema["children"].append(child_item) - input_widget = DictWidget( - item_schema, self, as_widget=True, label_widget=self.label_widget - ) + input_widget = DictWidget(item_schema, self, as_widget=True) + input_widget.create_ui(label_widget=self.label_widget) + self.content_layout.addWidget(input_widget) self.input_field = input_widget input_widget.value_changed.connect(self._on_value_change) @@ -3221,23 +3208,24 @@ class DictFormWidget(QtWidgets.QWidget, SettingObject): expand_in_grid = True def __init__( - self, input_data, parent, - as_widget=False, label_widget=None, parent_widget=None + self, schema_data, parent, as_widget=False, parent_widget=None ): if parent_widget is None: parent_widget = parent super(DictFormWidget, self).__init__(parent_widget) - self.initial_attributes(input_data, parent, as_widget) + self.initial_attributes(schema_data, parent, as_widget) self._as_widget = False self._is_group = False self.input_fields = [] + + def create_ui(self, label_widget=None): self.content_layout = QtWidgets.QFormLayout(self) self.content_layout.setContentsMargins(0, 0, 0, 0) - for child_data in input_data.get("children", []): + for child_data in self.schema_data.get("children", []): self.add_children_gui(child_data) self.setAttribute(QtCore.Qt.WA_TranslucentBackground) @@ -3260,7 +3248,8 @@ class DictFormWidget(QtWidgets.QWidget, SettingObject): label_widget = FormLabel(label, self) - item = klass(child_configuration, self, label_widget=label_widget) + item = klass(child_configuration, self) + item.create_ui(label_widget=label_widget) label_widget.item = item if item.hidden_by_role: From 5877e2246d8b324b87520b1a251b3a30f077512b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 11:49:30 +0100 Subject: [PATCH 107/279] added `is_wrapper_item` to determine if item may have any clue about it's `key` --- .../settings/settings/widgets/item_types.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 387398a32b..318f264f40 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -37,6 +37,9 @@ class SettingObject: """Partially abstract class for Setting's item type workflow.""" # `is_input_type` attribute says if has implemented item type methods is_input_type = True + # `is_wrapper_item` attribute says if item will never hold `key` + # information and is just visually different + is_wrapper_item = False # Each input must have implemented default value for development # when defaults are not filled yet. default_input_value = NOT_SET @@ -180,7 +183,17 @@ class SettingObject: self.hide() self.hidden_by_role = True - if not self.as_widget: + if ( + self.is_input_type + and not self.as_widget + and not self.is_wrapper_item + ): + if "key" not in self.schema_data: + error_msg = "Missing \"key\" in schema data. {}".format( + str(schema_data).replace("'", '"') + ) + raise KeyError(error_msg) + self.key = self.schema_data["key"] @property @@ -3206,6 +3219,7 @@ class DictFormWidget(QtWidgets.QWidget, SettingObject): value_changed = QtCore.Signal(object) allow_actions = False expand_in_grid = True + is_wrapper_item = True def __init__( self, schema_data, parent, as_widget=False, parent_widget=None From 5d66a25b78e87b94c1c11caea0c6eb2ff552c903 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Fri, 27 Nov 2020 12:05:21 +0100 Subject: [PATCH 108/279] change name of category --- .../gui_schemas/projects_schema/schema_anatomy_imageio.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_anatomy_imageio.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_anatomy_imageio.json index b7de6c5091..58852ba821 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_anatomy_imageio.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_anatomy_imageio.json @@ -1,7 +1,7 @@ { "type": "dict", "key": "imageio", - "label": "Color Management (Image i/o)", + "label": "Color Management and Output Formats", "is_file": true, "children": [{ "key": "hosts", From 7b1acfd60ddbf0fefdaa581ec614ece18fe3ade9 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 27 Nov 2020 12:07:50 +0100 Subject: [PATCH 109/279] feat(imageio): dropping `host` parent as it is redundant --- .../defaults/project_anatomy/imageio.json | 249 +++++---- .../schema_anatomy_imageio.json | 509 +++++++++--------- 2 files changed, 370 insertions(+), 388 deletions(-) diff --git a/pype/settings/defaults/project_anatomy/imageio.json b/pype/settings/defaults/project_anatomy/imageio.json index 1adab0fc2b..98ded33370 100644 --- a/pype/settings/defaults/project_anatomy/imageio.json +++ b/pype/settings/defaults/project_anatomy/imageio.json @@ -1,131 +1,122 @@ { - "hosts": { - "hiero": { - "workfile": { - "ocioConfigName": "nuke-default", - "ocioconfigpath": { - "windows": [], - "darwin": [], - "linux": [] - }, - "workingSpace": "linear", - "sixteenBitLut": "sRGB", - "eightBitLut": "sRGB", - "floatLut": "linear", - "logLut": "Cineon", - "viewerLut": "sRGB", - "thumbnailLut": "sRGB" - }, - "regexInputs": { - "inputs": [ - { - "regex": "[^-a-zA-Z0-9](plateRef).*(?=mp4)", - "colorspace": "sRGB" - } - ] - } - }, - "nuke": { - "workfile": { - "colorManagement": "Nuke", - "OCIO_config": "nuke-default", - "customOCIOConfigPath": { - "windows": [], - "darwin": [], - "linux": [] - }, - "workingSpaceLUT": "linear", - "monitorLut": "sRGB", - "int8Lut": "sRGB", - "int16Lut": "sRGB", - "logLut": "Cineon", - "floatLut": "linear" - }, - "nodes": { - "requiredNodes": [ - { - "plugins": [ - "CreateWriteRender" - ], - "nukeNodeClass": "Write", - "knobs": [ - { - "name": "file_type", - "value": "exr" - }, - { - "name": "datatype", - "value": "16 bit half" - }, - { - "name": "compression", - "value": "Zip (1 scanline)" - }, - { - "name": "autocrop", - "value": "True" - }, - { - "name": "tile_color", - "value": "0xff0000ff" - }, - { - "name": "channels", - "value": "rgb" - }, - { - "name": "colorspace", - "value": "linear" - } - ] - }, - { - "plugins": [ - "CreateWritePrerender" - ], - "nukeNodeClass": "Write", - "knobs": [ - { - "name": "file_type", - "value": "exr" - }, - { - "name": "datatype", - "value": "16 bit half" - }, - { - "name": "compression", - "value": "Zip (1 scanline)" - }, - { - "name": "autocrop", - "value": "False" - }, - { - "name": "tile_color", - "value": "0xff0000ff" - }, - { - "name": "channels", - "value": "rgb" - }, - { - "name": "colorspace", - "value": "linear" - } - ] - } - ], - "customNodes": [] - }, - "regexInputs": { - "inputs": [ - { - "regex": "[^-a-zA-Z0-9]beauty[^-a-zA-Z0-9]", - "colorspace": "linear" - } - ] - } - } + "hiero": { + "workfile": { + "ocioConfigName": "nuke-default", + "ocioconfigpath": { + "windows": [], + "darwin": [], + "linux": [] + }, + "workingSpace": "linear", + "sixteenBitLut": "sRGB", + "eightBitLut": "sRGB", + "floatLut": "linear", + "logLut": "Cineon", + "viewerLut": "sRGB", + "thumbnailLut": "sRGB" + }, + "regexInputs": { + "inputs": [{ + "regex": "[^-a-zA-Z0-9](plateRef).*(?=mp4)", + "colorspace": "sRGB" + }] } -} \ No newline at end of file + }, + "nuke": { + "workfile": { + "colorManagement": "Nuke", + "OCIO_config": "nuke-default", + "customOCIOConfigPath": { + "windows": [], + "darwin": [], + "linux": [] + }, + "workingSpaceLUT": "linear", + "monitorLut": "sRGB", + "int8Lut": "sRGB", + "int16Lut": "sRGB", + "logLut": "Cineon", + "floatLut": "linear" + }, + "nodes": { + "requiredNodes": [{ + "plugins": [ + "CreateWriteRender" + ], + "nukeNodeClass": "Write", + "knobs": [{ + "name": "file_type", + "value": "exr" + }, + { + "name": "datatype", + "value": "16 bit half" + }, + { + "name": "compression", + "value": "Zip (1 scanline)" + }, + { + "name": "autocrop", + "value": "True" + }, + { + "name": "tile_color", + "value": "0xff0000ff" + }, + { + "name": "channels", + "value": "rgb" + }, + { + "name": "colorspace", + "value": "linear" + } + ] + }, + { + "plugins": [ + "CreateWritePrerender" + ], + "nukeNodeClass": "Write", + "knobs": [{ + "name": "file_type", + "value": "exr" + }, + { + "name": "datatype", + "value": "16 bit half" + }, + { + "name": "compression", + "value": "Zip (1 scanline)" + }, + { + "name": "autocrop", + "value": "False" + }, + { + "name": "tile_color", + "value": "0xff0000ff" + }, + { + "name": "channels", + "value": "rgb" + }, + { + "name": "colorspace", + "value": "linear" + } + ] + } + ], + "customNodes": [] + }, + "regexInputs": { + "inputs": [{ + "regex": "[^-a-zA-Z0-9]beauty[^-a-zA-Z0-9]", + "colorspace": "linear" + }] + } + } +} diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_anatomy_imageio.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_anatomy_imageio.json index b7de6c5091..2057adfbbc 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_anatomy_imageio.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_anatomy_imageio.json @@ -4,294 +4,285 @@ "label": "Color Management (Image i/o)", "is_file": true, "children": [{ - "key": "hosts", + "key": "hiero", "type": "dict", - "label": "Hosts", - "collapsed": false, - "collapsable": true, + "label": "Hiero", "children": [{ - "key": "hiero", + "key": "workfile", "type": "dict", - "label": "Hiero", + "label": "Workfile", + "collapsable": false, "children": [{ - "key": "workfile", - "type": "dict", - "label": "Workfile", - "collapsable": false, + "type": "form", "children": [{ - "type": "form", - "children": [{ - "type": "enum", - "key": "ocioConfigName", - "label": "OpenColorIO Config", - "enum_items": [{ - "nuke-default": "nuke-default" - }, - { - "aces_1.0.3": "aces_1.0.3" - }, - { - "aces_1.1": "aces_1.1" - }, - { - "custom": "custom" - } - ] - }, { - "type": "path-widget", - "key": "ocioconfigpath", - "label": "Custom OCIO path", - "multiplatform": true, - "multipath": true - }, { - "type": "text", - "key": "workingSpace", - "label": "Working Space" - }, { - "type": "text", - "key": "sixteenBitLut", - "label": "16 Bit Files" - }, { - "type": "text", - "key": "eightBitLut", - "label": "8 Bit Files" - }, { - "type": "text", - "key": "floatLut", - "label": "Floating Point Files" - }, { - "type": "text", - "key": "logLut", - "label": "Log Files" - }, { - "type": "text", - "key": "viewerLut", - "label": "Viewer" - }, { - "type": "text", - "key": "thumbnailLut", - "label": "Thumbnails" - }] - }] - }, { - "key": "regexInputs", - "type": "dict", - "label": "Colorspace on Inputs by regex detection", - "collapsable": true, - "children": [{ - "type": "list", - "key": "inputs", - "label": "", - "object_type": { - "type": "dict", - "children": [{ - "type": "text", - "key": "regex", - "label": "Regex" - }, { - "type": "text", - "key": "colorspace", - "label": "Colorspace" - }] - } + "type": "enum", + "key": "ocioConfigName", + "label": "OpenColorIO Config", + "enum_items": [{ + "nuke-default": "nuke-default" + }, + { + "aces_1.0.3": "aces_1.0.3" + }, + { + "aces_1.1": "aces_1.1" + }, + { + "custom": "custom" + } + ] + }, { + "type": "path-widget", + "key": "ocioconfigpath", + "label": "Custom OCIO path", + "multiplatform": true, + "multipath": true + }, { + "type": "text", + "key": "workingSpace", + "label": "Working Space" + }, { + "type": "text", + "key": "sixteenBitLut", + "label": "16 Bit Files" + }, { + "type": "text", + "key": "eightBitLut", + "label": "8 Bit Files" + }, { + "type": "text", + "key": "floatLut", + "label": "Floating Point Files" + }, { + "type": "text", + "key": "logLut", + "label": "Log Files" + }, { + "type": "text", + "key": "viewerLut", + "label": "Viewer" + }, { + "type": "text", + "key": "thumbnailLut", + "label": "Thumbnails" }] }] }, { - "key": "nuke", + "key": "regexInputs", "type": "dict", - "label": "Nuke", + "label": "Colorspace on Inputs by regex detection", + "collapsable": true, "children": [{ - "key": "workfile", - "type": "dict", - "label": "Workfile", - "collapsable": false, - "is_group": true, - "children": [{ - "type": "form", + "type": "list", + "key": "inputs", + "label": "", + "object_type": { + "type": "dict", "children": [{ - "type": "enum", - "key": "colorManagement", - "label": "color management", - "enum_items": [{ - "Nuke": "Nuke" - }, - { - "OCIO": "OCIO" - } - ] - }, { - "type": "enum", - "key": "OCIO_config", - "label": "OpenColorIO Config", - "enum_items": [{ - "nuke-default": "nuke-default" - }, - { - "spi-vfx": "spi-vfx" - }, - { - "spi-anim": "spi-anim" - }, - { - "aces_1.0.3": "aces_0.1.1" - }, - { - "aces_1.0.3": "aces_0.7.1" - }, - { - "aces_1.0.3": "aces_1.0.1" - }, - { - "aces_1.0.3": "aces_1.0.3" - }, - { - "aces_1.1": "aces_1.1" - }, - { - "custom": "custom" - } - ] - }, { - "type": "path-widget", - "key": "customOCIOConfigPath", - "label": "Custom OCIO config path", - "multiplatform": true, - "multipath": true + "type": "text", + "key": "regex", + "label": "Regex" }, { "type": "text", - "key": "workingSpaceLUT", - "label": "Working Space" - }, { - "type": "text", - "key": "monitorLut", - "label": "monitor" - }, { - "type": "text", - "key": "int8Lut", - "label": "8-bit files" - }, { - "type": "text", - "key": "int16Lut", - "label": "16-bit files" - }, { - "type": "text", - "key": "logLut", - "label": "log files" - }, { - "type": "text", - "key": "floatLut", - "label": "float files" + "key": "colorspace", + "label": "Colorspace" }] + } + }] + }] + }, { + "key": "nuke", + "type": "dict", + "label": "Nuke", + "children": [{ + "key": "workfile", + "type": "dict", + "label": "Workfile", + "collapsable": false, + "is_group": true, + "children": [{ + "type": "form", + "children": [{ + "type": "enum", + "key": "colorManagement", + "label": "color management", + "enum_items": [{ + "Nuke": "Nuke" + }, + { + "OCIO": "OCIO" + } + ] + }, { + "type": "enum", + "key": "OCIO_config", + "label": "OpenColorIO Config", + "enum_items": [{ + "nuke-default": "nuke-default" + }, + { + "spi-vfx": "spi-vfx" + }, + { + "spi-anim": "spi-anim" + }, + { + "aces_1.0.3": "aces_0.1.1" + }, + { + "aces_1.0.3": "aces_0.7.1" + }, + { + "aces_1.0.3": "aces_1.0.1" + }, + { + "aces_1.0.3": "aces_1.0.3" + }, + { + "aces_1.1": "aces_1.1" + }, + { + "custom": "custom" + } + ] + }, { + "type": "path-widget", + "key": "customOCIOConfigPath", + "label": "Custom OCIO config path", + "multiplatform": true, + "multipath": true + }, { + "type": "text", + "key": "workingSpaceLUT", + "label": "Working Space" + }, { + "type": "text", + "key": "monitorLut", + "label": "monitor" + }, { + "type": "text", + "key": "int8Lut", + "label": "8-bit files" + }, { + "type": "text", + "key": "int16Lut", + "label": "16-bit files" + }, { + "type": "text", + "key": "logLut", + "label": "log files" + }, { + "type": "text", + "key": "floatLut", + "label": "float files" }] - }, { - "key": "nodes", - "type": "dict", - "label": "Nodes", - "collapsable": true, - "is_group": true, - "children": [ - { - "key": "requiredNodes", + }] + }, { + "key": "nodes", + "type": "dict", + "label": "Nodes", + "collapsable": true, + "is_group": true, + "children": [{ + "key": "requiredNodes", + "type": "list", + "label": "Required Nodes", + "object_type": { + "type": "dict", + "children": [{ "type": "list", - "label": "Required Nodes", + "key": "plugins", + "label": "Used in plugins", "object_type": { - "type": "dict", - "children": [{ - "type": "list", - "key": "plugins", - "label": "Used in plugins", - "object_type": { - "type": "text", - "key": "pluginClass", - "label": "Plugin Class" - } - }, { - "type": "text", - "key": "nukeNodeClass", - "label": "Nuke Node Class" - }, { - "type": "splitter" - }, { - "key": "knobs", - "label": "Knobs", - "type": "list", - "object_type": { - "type": "dict", - "children": [{ - "type": "text", - "key": "name", - "label": "Name" - }, { - "type": "text", - "key": "value", - "label": "Value" - }] - } - }] + "type": "text", + "key": "pluginClass", + "label": "Plugin Class" } }, { + "type": "text", + "key": "nukeNodeClass", + "label": "Nuke Node Class" + }, { + "type": "splitter" + }, { + "key": "knobs", + "label": "Knobs", "type": "list", - "key": "customNodes", - "label": "Custom Nodes", "object_type": { "type": "dict", "children": [{ - "type": "list", - "key": "plugins", - "label": "Used in plugins", - "object_type": { - "type": "text", - "key": "pluginClass", - "label": "Plugin Class" - } + "type": "text", + "key": "name", + "label": "Name" }, { "type": "text", - "key": "nukeNodeClass", - "label": "Nuke Node Class" - }, { - "type": "splitter" - }, { - "key": "knobs", - "label": "Knobs", - "type": "list", - "object_type": { - "type": "dict", - "children": [{ - "type": "text", - "key": "name", - "label": "Name" - }, { - "type": "text", - "key": "value", - "label": "Value" - }] - } + "key": "value", + "label": "Value" }] } - } - ] + }] + } }, { - "key": "regexInputs", - "type": "dict", - "label": "Colorspace on Inputs by regex detection", - "collapsable": true, - "children": [{ - "type": "list", - "key": "inputs", - "label": "", - "object_type": { - "type": "dict", - "children": [{ + "type": "list", + "key": "customNodes", + "label": "Custom Nodes", + "object_type": { + "type": "dict", + "children": [{ + "type": "list", + "key": "plugins", + "label": "Used in plugins", + "object_type": { "type": "text", - "key": "regex", - "label": "Regex" - }, { - "type": "text", - "key": "colorspace", - "label": "Colorspace" - }] - } - }] + "key": "pluginClass", + "label": "Plugin Class" + } + }, { + "type": "text", + "key": "nukeNodeClass", + "label": "Nuke Node Class" + }, { + "type": "splitter" + }, { + "key": "knobs", + "label": "Knobs", + "type": "list", + "object_type": { + "type": "dict", + "children": [{ + "type": "text", + "key": "name", + "label": "Name" + }, { + "type": "text", + "key": "value", + "label": "Value" + }] + } + }] + } + }] + }, { + "key": "regexInputs", + "type": "dict", + "label": "Colorspace on Inputs by regex detection", + "collapsable": true, + "children": [{ + "type": "list", + "key": "inputs", + "label": "", + "object_type": { + "type": "dict", + "children": [{ + "type": "text", + "key": "regex", + "label": "Regex" + }, { + "type": "text", + "key": "colorspace", + "label": "Colorspace" + }] + } }] }] }] From ae657498e3dfaf5db3b273519cb5a4e07ef7b1e7 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 27 Nov 2020 12:30:39 +0100 Subject: [PATCH 110/279] fix extract look file check --- pype/plugins/maya/publish/extract_look.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/plugins/maya/publish/extract_look.py b/pype/plugins/maya/publish/extract_look.py index 6bd202093f..7a5dc25fcf 100644 --- a/pype/plugins/maya/publish/extract_look.py +++ b/pype/plugins/maya/publish/extract_look.py @@ -350,7 +350,7 @@ class ExtractLook(pype.api.Extractor): if existing and not force: self.log.info("Found hash in database, preparing hardlink..") source = next((p for p in existing if os.path.exists(p)), None) - if filepath: + if source: return source, HARDLINK, texture_hash else: self.log.warning( From 7b025ffc830ac027c62227579204d1593415faf5 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 27 Nov 2020 13:07:26 +0100 Subject: [PATCH 111/279] Committing again after rebase Add pulling extension from AE Render Queue Add pulling information about audio layer for composition --- .../stubs/aftereffects_server_stub.py | 32 ++++++++++++++++ .../aftereffects/publish/collect_audio.py | 27 +++++++++++++ .../aftereffects/publish/collect_render.py | 31 ++++++++++----- .../publish/submit_aftereffects_deadline.py | 38 ++++++++++++------- 4 files changed, 106 insertions(+), 22 deletions(-) create mode 100644 pype/plugins/aftereffects/publish/collect_audio.py diff --git a/pype/modules/websocket_server/stubs/aftereffects_server_stub.py b/pype/modules/websocket_server/stubs/aftereffects_server_stub.py index 84dce39a41..e47aaee471 100644 --- a/pype/modules/websocket_server/stubs/aftereffects_server_stub.py +++ b/pype/modules/websocket_server/stubs/aftereffects_server_stub.py @@ -252,6 +252,9 @@ class AfterEffectsServerStub(): Args: item_id (int): + Returns: + (namedtuple) + """ res = self.websocketserver.call(self.client.call ('AfterEffects.get_work_area', @@ -305,6 +308,35 @@ class AfterEffectsServerStub(): image_path=project_path, as_copy=as_copy)) + def get_render_info(self): + """ Get render queue info for render purposes + + Returns: + (namedtuple): with 'file_name' field + """ + res = self.websocketserver.call(self.client.call + ('AfterEffects.get_render_info')) + + records = self._to_records(res) + if records: + return records.pop() + + log.debug("Couldn't get render queue info") + + def get_audio_url(self, item_id): + """ Get audio layer absolute url for comp + + Args: + item_id (int): composition id + Returns: + (str): absolute path url + """ + res = self.websocketserver.call(self.client.call + ('AfterEffects.get_audio_url', + item_id=item_id)) + + return res + def close(self): self.client.close() diff --git a/pype/plugins/aftereffects/publish/collect_audio.py b/pype/plugins/aftereffects/publish/collect_audio.py new file mode 100644 index 0000000000..37938eb6a6 --- /dev/null +++ b/pype/plugins/aftereffects/publish/collect_audio.py @@ -0,0 +1,27 @@ +import os + +import pyblish.api + +from avalon import aftereffects + + +class CollectAudio(pyblish.api.ContextPlugin): + """Inject audio file url for rendered composition into context. + Needs to run AFTER 'collect_render'. Use collected comp_id to check + if there is an AVLayer in this composition + """ + + order = pyblish.api.CollectorOrder + 0.499 + label = "Collect Audio" + hosts = ["aftereffects"] + + def process(self, context): + for instance in context: + if instance.data["family"] == 'render.farm': + comp_id = instance.data["comp_id"] + if not comp_id: + self.log.debug("No comp_id filled in instance") + return + context.data["audioFile"] = os.path.normpath( + aftereffects.stub().get_audio_url(comp_id) + ).replace("\\", "/") diff --git a/pype/plugins/aftereffects/publish/collect_render.py b/pype/plugins/aftereffects/publish/collect_render.py index 13ffc3f208..f053eb7ce3 100644 --- a/pype/plugins/aftereffects/publish/collect_render.py +++ b/pype/plugins/aftereffects/publish/collect_render.py @@ -11,6 +11,7 @@ from avalon import aftereffects class AERenderInstance(RenderInstance): # extend generic, composition name is needed comp_name = attr.ib(default=None) + comp_id = attr.ib(default=None) class CollectAERender(abstract_collect_render.AbstractCollectRender): @@ -83,6 +84,7 @@ class CollectAERender(abstract_collect_render.AbstractCollectRender): raise ValueError("There is no composition for item {}". format(item_id)) instance.comp_name = comp.name + instance.comp_id = item_id instance._anatomy = context.data["anatomy"] instance.anatomyData = context.data["anatomyData"] @@ -108,18 +110,29 @@ class CollectAERender(abstract_collect_render.AbstractCollectRender): start = render_instance.frameStart end = render_instance.frameEnd + # pull file name from Render Queue Output module + render_q = aftereffects.stub().get_render_info() + _, ext = os.path.splitext(os.path.basename(render_q.file_name)) base_dir = self._get_output_dir(render_instance) expected_files = [] - for frame in range(start, end + 1): - path = os.path.join(base_dir, "{}_{}_{}.{}.{}".format( - render_instance.asset, - render_instance.subset, - "v{:03d}".format(render_instance.version), - str(frame).zfill(self.padding_width), - self.rendered_extension - )) + if "#" not in render_q.file_name: # single frame (mov)W + path = os.path.join(base_dir, "{}_{}_{}.{}".format( + render_instance.asset, + render_instance.subset, + "v{:03d}".format(render_instance.version), + ext.replace('.', '') + )) expected_files.append(path) - + else: + for frame in range(start, end + 1): + path = os.path.join(base_dir, "{}_{}_{}.{}.{}".format( + render_instance.asset, + render_instance.subset, + "v{:03d}".format(render_instance.version), + str(frame).zfill(self.padding_width), + ext.replace('.', '') + )) + expected_files.append(path) return expected_files def _get_output_dir(self, render_instance): diff --git a/pype/plugins/aftereffects/publish/submit_aftereffects_deadline.py b/pype/plugins/aftereffects/publish/submit_aftereffects_deadline.py index 15d9e216fb..8bb42a0239 100644 --- a/pype/plugins/aftereffects/publish/submit_aftereffects_deadline.py +++ b/pype/plugins/aftereffects/publish/submit_aftereffects_deadline.py @@ -18,6 +18,7 @@ class DeadlinePluginInfo(): ProjectPath = attr.ib(default=None) AWSAssetFile0 = attr.ib(default=None) Version = attr.ib(default=None) + MultiProcess = attr.ib(default=None) class AfterEffectsSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): @@ -39,9 +40,14 @@ class AfterEffectsSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline dln_job_info.Plugin = "AfterEffects" dln_job_info.UserName = context.data.get( "deadlineUser", getpass.getuser()) - frame_range = "{}-{}".format(self._instance.data["frameStart"], - self._instance.data["frameEnd"]) - dln_job_info.Frames = frame_range + if self._instance.data["frameEnd"] > self._instance.data["frameStart"]: + frame_range = "{}-{}".format(self._instance.data["frameStart"], + self._instance.data["frameEnd"]) + dln_job_info.Frames = frame_range + + if len(self._instance.data["expectedFiles"]) == 1: + dln_job_info.ChunkSize = 1000000 + dln_job_info.OutputFilename = \ os.path.basename(self._instance.data["expectedFiles"][0]) dln_job_info.OutputDirectory = \ @@ -77,17 +83,23 @@ class AfterEffectsSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline script_path = context.data["currentFile"] render_path = self._instance.data["expectedFiles"][0] - # replace frame info ('000001') with Deadline's required '[#######]' - # expects filename in format project_asset_subset_version.FRAME.ext - render_dir = os.path.dirname(render_path) - file_name = os.path.basename(render_path) - arr = file_name.split('.') - assert len(arr) == 3, \ - "Unable to parse frames from {}".format(file_name) - hashed = '[{}]'.format(len(arr[1]) * "#") - render_path = os.path.join(render_dir, - '{}.{}.{}'.format(arr[0], hashed, arr[2])) + if len(self._instance.data["expectedFiles"]) > 1: + # replace frame ('000001') with Deadline's required '[#######]' + # expects filename in format project_asset_subset_version.FRAME.ext + render_dir = os.path.dirname(render_path) + file_name = os.path.basename(render_path) + arr = file_name.split('.') + assert len(arr) == 3, \ + "Unable to parse frames from {}".format(file_name) + hashed = '[{}]'.format(len(arr[1]) * "#") + + render_path = os.path.join(render_dir, + '{}.{}.{}'.format(arr[0], hashed, + arr[2])) + deadline_plugin_info.MultiProcess = True + else: + deadline_plugin_info.MultiProcess = False deadline_plugin_info.Comp = self._instance.data["comp_name"] deadline_plugin_info.Version = "17.5" From 170d1b01883ae9103f90e0f538b118f5e2b5e2ea Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 14:25:56 +0100 Subject: [PATCH 112/279] fixed Expanding widget --- pype/tools/settings/settings/widgets/widgets.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/widgets.py b/pype/tools/settings/settings/widgets/widgets.py index b64b1aa8ac..6135f8dcb2 100644 --- a/pype/tools/settings/settings/widgets/widgets.py +++ b/pype/tools/settings/settings/widgets/widgets.py @@ -112,7 +112,7 @@ class ExpandingWidget(QtWidgets.QWidget): before_label_layout.setContentsMargins(0, 0, 0, 0) after_label_widget = QtWidgets.QWidget(side_line_widget) - after_label_layout = QtWidgets.QVBoxLayout(after_label_widget) + after_label_layout = QtWidgets.QHBoxLayout(after_label_widget) after_label_layout.setContentsMargins(0, 0, 0, 0) spacer_widget = QtWidgets.QWidget(side_line_widget) @@ -158,6 +158,12 @@ class ExpandingWidget(QtWidgets.QWidget): self.content_widget.setVisible(not hide_content) self.parent().updateGeometry() + def show_toolbox(self): + self.toolbox_hidden = False + self.toggle_content(self.button_toggle.isChecked()) + + self.parent().updateGeometry() + def set_content_widget(self, content_widget): content_widget.setVisible(False) self.main_layout.addWidget(content_widget) From 3c0de1cbd42a1e64af76d700580eb41e6e971431 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 14:33:38 +0100 Subject: [PATCH 113/279] preparations for labeled item --- .../settings/settings/widgets/item_types.py | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 318f264f40..f83e406815 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1970,11 +1970,11 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(3) - ItemKlass = TypeToKlass.types[item_schema["type"]] self.key_input = QtWidgets.QLineEdit(self) self.key_input.setObjectName("DictKey") + ItemKlass = TypeToKlass.types[item_schema["type"]] self.value_input = ItemKlass( item_schema, self, @@ -2013,6 +2013,10 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self.origin_key = NOT_SET + @property + def labeled_items(self): + return self._parent.labeled_items + def key_value(self): return self.key_input.text() @@ -2028,8 +2032,9 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): return False def _on_key_change(self): + value = self.key_input.text() if self.value_is_env_group: - self.value_input.env_group_key = self.key_input.text() + self.value_input.env_group_key = value self._on_value_change() def _on_value_change(self, item=None): @@ -2066,6 +2071,9 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self._parent.add_row(row=self.row() + 1) def on_remove_clicked(self): + self.remove_row() + + def remove_row(self): self._parent.remove_row(self) def set_as_empty(self, is_empty=True): @@ -2156,7 +2164,8 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.value_is_env_group = ( schema_data.get("value_is_env_group") or False ) - self.hightlight_content = self.schema_data.get("highlight_content") + self.hightlight_content = schema_data.get("highlight_content") or False + self.labeled_items = schema_data.get("labeled_items") or False object_type = schema_data["object_type"] if isinstance(object_type, dict): @@ -2365,15 +2374,24 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.input_fields.insert(row, item_widget) previous_input = None - for input_field in self.input_fields: - if previous_input is not None: + if self.labeled_items: + for input_field in self.input_fields: + if previous_input is not None: + self.setTabOrder( + previous_input, input_field.value_input + ) + previous_input = input_field.value_input.focusProxy() + + else: + for input_field in self.input_fields: + if previous_input is not None: + self.setTabOrder( + previous_input, input_field.key_input + ) + previous_input = input_field.value_input.focusProxy() self.setTabOrder( - previous_input, input_field.key_input + input_field.key_input, previous_input ) - previous_input = input_field.value_input.focusProxy() - self.setTabOrder( - input_field.key_input, previous_input - ) # Set value if entered value is not None # else (when add button clicked) trigger `_on_value_change` From 6f6678a5bf50c5dbb6f5c9fcb14fda6ee227e97d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 14:35:58 +0100 Subject: [PATCH 114/279] moved key input --- pype/tools/settings/settings/widgets/item_types.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index f83e406815..c35ae96635 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1971,8 +1971,6 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): layout.setSpacing(3) - self.key_input = QtWidgets.QLineEdit(self) - self.key_input.setObjectName("DictKey") ItemKlass = TypeToKlass.types[item_schema["type"]] self.value_input = ItemKlass( @@ -1984,6 +1982,8 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self.add_btn = QtWidgets.QPushButton("+") self.remove_btn = QtWidgets.QPushButton("-") + self.key_input = QtWidgets.QLineEdit(self.wrapper_widget or self) + self.key_input.setObjectName("DictKey") self.add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) self.remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) From d7289f0fc091ca7b9d4a94bd99f21a70b624c9ce Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 14:36:15 +0100 Subject: [PATCH 115/279] different init if labeld item --- .../settings/settings/widgets/item_types.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index c35ae96635..716b63cf91 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1966,11 +1966,25 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self._is_empty = False self.is_key_duplicated = False - layout = QtWidgets.QHBoxLayout(self) + if self.labeled_items: + layout = QtWidgets.QVBoxLayout(self) + else: + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(3) + self.wrapper_widget = None + if self.labeled_items: + self.wrapper_widget = ExpandingWidget("", self) + layout.addWidget(self.wrapper_widget) + content_widget = QtWidgets.QWidget(self.wrapper_widget) + content_layout = QtWidgets.QHBoxLayout(content_widget) + content_layout.setContentsMargins(0, 0, 0, 0) + content_layout.setSpacing(3) + + self.wrapper_widget.set_content_widget(content_widget) ItemKlass = TypeToKlass.types[item_schema["type"]] self.value_input = ItemKlass( From c9c23658112a10f053a09378fda9d7236f80217f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 14:48:15 +0100 Subject: [PATCH 116/279] set_as_empty has separated logic --- .../settings/settings/widgets/item_types.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 716b63cf91..aa265caec9 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2093,10 +2093,22 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): def set_as_empty(self, is_empty=True): self._is_empty = is_empty - self.key_input.setVisible(not is_empty) self.value_input.setVisible(not is_empty) - self.remove_btn.setEnabled(not is_empty) - self.spacer_widget.setVisible(is_empty) + self.add_btn.setVisible(is_empty) + if not self.labeled_items: + self.key_input.setVisible(not is_empty) + self.remove_btn.setEnabled(not is_empty) + self.spacer_widget.setVisible(is_empty) + + else: + self.key_input.setVisible(is_empty) + self.edit_btn.setVisible(not is_empty) + + self.wrapper_widget.label_widget.setVisible(not is_empty) + if is_empty: + self.wrapper_widget.hide_toolbox() + else: + self.wrapper_widget.show_toolbox() self._on_value_change() @property From aae2d448dd4f14e88eee8eb17dea5b788bb55251 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 14:49:00 +0100 Subject: [PATCH 117/279] add_clicked has separated logic --- .../settings/settings/widgets/item_types.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index aa265caec9..e16fd0700c 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2079,10 +2079,21 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): return self._parent.is_group def on_add_clicked(self): - if self._is_empty: - self.set_as_empty(False) - else: - self._parent.add_row(row=self.row() + 1) + if not self.labeled_items: + if self._is_empty: + self.set_as_empty(False) + else: + self._parent.add_row(row=self.row() + 1) + return + + if not self._is_empty: + return + + if not self.key_value(): + return + + self.set_as_empty(False) + self._parent.add_row(row=self.row() + 1, is_empty=True) def on_remove_clicked(self): self.remove_row() From ea19cfcae075b8d46ece5e242422e0fc03310310 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 14:49:22 +0100 Subject: [PATCH 118/279] change_key_label implemented to change label --- pype/tools/settings/settings/widgets/item_types.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index e16fd0700c..db8f8aa973 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2049,6 +2049,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): value = self.key_input.text() if self.value_is_env_group: self.value_input.env_group_key = value + self.change_key_label(value) self._on_value_change() def _on_value_change(self, item=None): @@ -2078,6 +2079,10 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): def is_group(self): return self._parent.is_group + def change_key_label(self, label): + if self.wrapper_widget: + self.wrapper_widget.label_widget.setText(label) + def on_add_clicked(self): if not self.labeled_items: if self._is_empty: From 96b8916147d2cf1780df8c7ed4cd7a103023e971 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 14:50:06 +0100 Subject: [PATCH 119/279] implemented empty `on_edit_clicked` method --- pype/tools/settings/settings/widgets/item_types.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index db8f8aa973..aac2c6aa37 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2100,6 +2100,9 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self.set_as_empty(False) self._parent.add_row(row=self.row() + 1, is_empty=True) + def on_edit_clicked(self): + print("Edit triggered") + def on_remove_clicked(self): self.remove_row() From f69ec9f45ef04d9bbb185c1800a665ef2a7e3b2f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 14:50:19 +0100 Subject: [PATCH 120/279] separated item initialization --- .../settings/settings/widgets/item_types.py | 109 +++++++++++------- 1 file changed, 70 insertions(+), 39 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index aac2c6aa37..265911f914 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1966,6 +1966,8 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self._is_empty = False self.is_key_duplicated = False + self.origin_key = NOT_SET + if self.labeled_items: layout = QtWidgets.QVBoxLayout(self) else: @@ -1974,58 +1976,87 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(3) - self.wrapper_widget = None - if self.labeled_items: - self.wrapper_widget = ExpandingWidget("", self) - layout.addWidget(self.wrapper_widget) - - content_widget = QtWidgets.QWidget(self.wrapper_widget) - content_layout = QtWidgets.QHBoxLayout(content_widget) - content_layout.setContentsMargins(0, 0, 0, 0) - content_layout.setSpacing(3) - - self.wrapper_widget.set_content_widget(content_widget) - ItemKlass = TypeToKlass.types[item_schema["type"]] - self.value_input = ItemKlass( + value_input = ItemKlass( item_schema, self, as_widget=True ) - self.value_input.create_ui() + value_input.create_ui() - self.add_btn = QtWidgets.QPushButton("+") - self.remove_btn = QtWidgets.QPushButton("-") - self.key_input = QtWidgets.QLineEdit(self.wrapper_widget or self) - self.key_input.setObjectName("DictKey") + wrapper_widget = None + if self.labeled_items: + wrapper_widget = ExpandingWidget("", self) + layout.addWidget(wrapper_widget) - self.add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - self.remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + content_widget = QtWidgets.QWidget(wrapper_widget) + content_layout = QtWidgets.QHBoxLayout(content_widget) + content_layout.setContentsMargins(0, 0, 0, 0) + content_layout.setSpacing(3) - self.add_btn.setProperty("btn-type", "tool-item") - self.remove_btn.setProperty("btn-type", "tool-item") + wrapper_widget.set_content_widget(content_widget) - self.spacer_widget = QtWidgets.QWidget(self) - self.spacer_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) - self.spacer_widget.setVisible(False) + content_layout.addWidget(value_input) - layout.addWidget(self.add_btn, 0) - layout.addWidget(self.remove_btn, 0) - layout.addWidget(self.key_input, 0) - layout.addWidget(self.spacer_widget, 1) - layout.addWidget(self.value_input, 1) + key_input = QtWidgets.QLineEdit(wrapper_widget or self) + key_input.setObjectName("DictKey") - self.setFocusProxy(self.value_input) + spacer_widget = None + if not self.labeled_items: + spacer_widget = QtWidgets.QWidget(self) + spacer_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + spacer_widget.setVisible(False) - self.add_btn.setFixedSize(self._btn_size, self._btn_size) - self.remove_btn.setFixedSize(self._btn_size, self._btn_size) - self.add_btn.clicked.connect(self.on_add_clicked) - self.remove_btn.clicked.connect(self.on_remove_clicked) + add_btn = QtWidgets.QPushButton("+") + add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + add_btn.setProperty("btn-type", "tool-item") + add_btn.setFixedSize(self._btn_size, self._btn_size) - self.key_input.textChanged.connect(self._on_key_change) - self.value_input.value_changed.connect(self._on_value_change) + edit_btn = None + remove_btn = None + if self.labeled_items: + edit_btn = QtWidgets.QPushButton("Edit") + edit_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + edit_btn.setProperty("btn-type", "tool-item") + edit_btn.setFixedSize(self._btn_size, self._btn_size) + else: + remove_btn = QtWidgets.QPushButton("-") + remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + remove_btn.setProperty("btn-type", "tool-item") + remove_btn.setFixedSize(self._btn_size, self._btn_size) - self.origin_key = NOT_SET + if self.labeled_items: + wrapper_widget.add_widget_after_label(key_input) + wrapper_widget.add_widget_after_label(add_btn) + wrapper_widget.add_widget_after_label(edit_btn) + + else: + layout.addWidget(add_btn, 0) + layout.addWidget(remove_btn, 0) + layout.addWidget(key_input, 0) + layout.addWidget(spacer_widget, 1) + layout.addWidget(value_input, 1) + + self.setFocusProxy(value_input) + + key_input.textChanged.connect(self._on_key_change) + value_input.value_changed.connect(self._on_value_change) + add_btn.clicked.connect(self.on_add_clicked) + if edit_btn: + edit_btn.clicked.connect(self.on_edit_clicked) + if remove_btn: + remove_btn.clicked.connect(self.on_remove_clicked) + + self.key_input = key_input + self.value_input = value_input + + self.wrapper_widget = wrapper_widget + + self.spacer_widget = spacer_widget + + self.add_btn = add_btn + self.edit_btn = edit_btn + self.remove_btn = remove_btn @property def labeled_items(self): @@ -2101,7 +2132,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self._parent.add_row(row=self.row() + 1, is_empty=True) def on_edit_clicked(self): - print("Edit triggered") + pass def on_remove_clicked(self): self.remove_row() From 6a98818834f663ca147001e94c61827514004ded Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 15:03:13 +0100 Subject: [PATCH 121/279] handledimplemented basic adding new items --- .../settings/settings/widgets/item_types.py | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 265911f914..e678651545 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2000,6 +2000,11 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): key_input = QtWidgets.QLineEdit(wrapper_widget or self) key_input.setObjectName("DictKey") + if self.labeled_items: + def focused_out(event): + super(QtWidgets.QLineEdit, key_input).focusOutEvent(event) + self._on_enter_press() + key_input.focusOutEvent = focused_out spacer_widget = None if not self.labeled_items: @@ -2040,6 +2045,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self.setFocusProxy(value_input) key_input.textChanged.connect(self._on_key_change) + key_input.returnPressed.connect(self._on_enter_press) value_input.value_changed.connect(self._on_value_change) add_btn.clicked.connect(self.on_add_clicked) if edit_btn: @@ -2076,6 +2082,15 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): return True return False + def _on_enter_press(self): + if not self.labeled_items: + return + + if self._is_empty: + self.on_add_clicked() + else: + self.set_edit_mode(False) + def _on_key_change(self): value = self.key_input.text() if self.value_is_env_group: @@ -2132,7 +2147,11 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self._parent.add_row(row=self.row() + 1, is_empty=True) def on_edit_clicked(self): - pass + self.set_edit_mode() + + def set_edit_mode(self, enabled=True): + self.key_input.setVisible(enabled) + self.wrapper_widget.label_widget.setVisible(not enabled) def on_remove_clicked(self): self.remove_row() From 06413e5a1bf0a525a0e687438d81a9d14c3e71f0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 15:09:58 +0100 Subject: [PATCH 122/279] fixed state styles --- pype/tools/settings/settings/widgets/item_types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index e678651545..cd586a71ea 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1998,7 +1998,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): content_layout.addWidget(value_input) - key_input = QtWidgets.QLineEdit(wrapper_widget or self) + key_input = QtWidgets.QLineEdit(self) key_input.setObjectName("DictKey") if self.labeled_items: def focused_out(event): From f6885cdd9cadc41cbeb89e58f99efa95a6d5ebf9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 15:10:16 +0100 Subject: [PATCH 123/279] fixed focus out --- pype/tools/settings/settings/widgets/item_types.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index cd586a71ea..e23390a7e4 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2002,8 +2002,9 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): key_input.setObjectName("DictKey") if self.labeled_items: def focused_out(event): - super(QtWidgets.QLineEdit, key_input).focusOutEvent(event) + QtWidgets.QLineEdit.focusOutEvent(key_input, event) self._on_enter_press() + key_input.focusOutEvent = focused_out spacer_widget = None @@ -2150,8 +2151,10 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self.set_edit_mode() def set_edit_mode(self, enabled=True): - self.key_input.setVisible(enabled) self.wrapper_widget.label_widget.setVisible(not enabled) + self.key_input.setVisible(enabled) + if enabled: + self.key_input.setFocus() def on_remove_clicked(self): self.remove_row() From 098b2e295ba1d66d448d7a01fb8850e0721a3c72 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 27 Nov 2020 15:14:19 +0100 Subject: [PATCH 124/279] handle vray aov names --- pype/hosts/maya/expected_files.py | 62 +++++++++++++++++++------------ 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/pype/hosts/maya/expected_files.py b/pype/hosts/maya/expected_files.py index bd58b10d74..344d32f144 100644 --- a/pype/hosts/maya/expected_files.py +++ b/pype/hosts/maya/expected_files.py @@ -418,13 +418,12 @@ class AExpectedFiles: if connections: for connection in connections: if connection: - node_name = connection.split(".")[0] - if cmds.nodeType(node_name) == "renderLayer": - attr_name = "%s.value" % ".".join( - connection.split(".")[:-1] - ) - if node_name == layer: - yield cmds.getAttr(attr_name) + # node_name = connection.split(".")[0] + + attr_name = "%s.value" % ".".join( + connection.split(".")[:-1] + ) + yield cmds.getAttr(attr_name) def get_render_attribute(self, attr): """Get attribute from render options. @@ -642,25 +641,42 @@ class ExpectedFilesVray(AExpectedFiles): return enabled_aovs def _get_vray_aov_name(self, node): + """Get AOVs name from Vray. - # Get render element pass type - vray_node_attr = next( - attr - for attr in cmds.listAttr(node) - if attr.startswith("vray_name") - ) - pass_type = vray_node_attr.rsplit("_", 1)[-1] + Args: + node (str): aov node name. - # Support V-Ray extratex explicit name (if set by user) - if pass_type == "extratex": - explicit_attr = "{}.vray_explicit_name_extratex".format(node) - explicit_name = cmds.getAttr(explicit_attr) - if explicit_name: - return explicit_name + Returns: + str: aov name. - # Node type is in the attribute name but we need to check if value - # of the attribute as it can be changed - return cmds.getAttr("{}.{}".format(node, vray_node_attr)) + """ + vray_name = None + vray_explicit_name = None + vray_file_name = None + for attr in cmds.listAttr(node): + if attr.startswith("vray_filename"): + vray_file_name = cmds.getAttr("{}.{}".format(node, attr)) + elif attr.startswith("vray_name"): + vray_name = cmds.getAttr("{}.{}".format(node, attr)) + elif attr.startswith("vray_explicit_name"): + vray_explicit_name = cmds.getAttr("{}.{}".format(node, attr)) + + if vray_file_name is not None and vray_file_name != "": + final_name = vray_file_name + elif vray_explicit_name is not None and vray_explicit_name != "": + final_name = vray_explicit_name + elif vray_name is not None and vray_name != "": + final_name = vray_name + else: + continue + # special case for Material Select elements - these are named based on the material + # they are connected to. + if "vray_mtl_mtlselect" in cmds.listAttr(node): + connections = cmds.listConnections("{}.vray_mtl_mtlselect".format(node)) + if connections: + final_name += '_{}'.format(str(connections[0])) + + return final_name class ExpectedFilesRedshift(AExpectedFiles): From caf4d94b567a0ea922c18a185c9fc9979b3649b6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 15:29:33 +0100 Subject: [PATCH 125/279] key dulication is handled better --- .../settings/settings/widgets/item_types.py | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index e23390a7e4..775408cb25 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1964,7 +1964,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self._any_parent_is_group = True self._is_empty = False - self.is_key_duplicated = False + self._is_key_duplicated = False self.origin_key = NOT_SET @@ -2079,10 +2079,19 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): if self.key_value() == "": return True - if self.is_key_duplicated: + if self._is_key_duplicated: return True return False + def set_key_is_duplicated(self, duplicated): + if duplicated == self._is_key_duplicated: + return + + self._is_key_duplicated = duplicated + if duplicated and self.labeled_items: + self.set_edit_mode(True) + self.update_style() + def _on_enter_press(self): if not self.labeled_items: return @@ -2151,6 +2160,8 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self.set_edit_mode() def set_edit_mode(self, enabled=True): + if self.is_invalid and not enabled: + return self.wrapper_widget.label_widget.setVisible(not enabled) self.key_input.setVisible(enabled) if enabled: @@ -2375,13 +2386,10 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): for fields in fields_by_keys.values(): if len(fields) == 1: field = fields[0] - if field.is_key_duplicated: - field.is_key_duplicated = False - field.update_style() + field.set_key_is_duplicated(False) else: for field in fields: - field.is_key_duplicated = True - field.update_style() + field.set_key_is_duplicated(True) if self.is_overidable: self._is_overriden = True From 8c6ad61256c7b2cc27a196abc169bb4cfa8cc8f0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 15:29:44 +0100 Subject: [PATCH 126/279] content layout has better margins --- pype/tools/settings/settings/widgets/item_types.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 775408cb25..8b689ecd1a 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1991,8 +1991,8 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): content_widget = QtWidgets.QWidget(wrapper_widget) content_layout = QtWidgets.QHBoxLayout(content_widget) - content_layout.setContentsMargins(0, 0, 0, 0) - content_layout.setSpacing(3) + content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) + content_layout.setSpacing(5) wrapper_widget.set_content_widget(content_widget) From c5ca4d10bbb6a8bae9a749cb7fde1d6a5bcd1184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Fri, 27 Nov 2020 16:03:40 +0100 Subject: [PATCH 127/279] hound stuff --- pype/hosts/maya/expected_files.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pype/hosts/maya/expected_files.py b/pype/hosts/maya/expected_files.py index 344d32f144..0b9b7d21d1 100644 --- a/pype/hosts/maya/expected_files.py +++ b/pype/hosts/maya/expected_files.py @@ -583,7 +583,7 @@ class ExpectedFilesVray(AExpectedFiles): expected_files[0].update(update) return expected_files - + def get_aovs(self): """Get all AOVs. @@ -669,10 +669,11 @@ class ExpectedFilesVray(AExpectedFiles): final_name = vray_name else: continue - # special case for Material Select elements - these are named based on the material - # they are connected to. + # special case for Material Select elements - these are named + # based on the materia they are connected to. if "vray_mtl_mtlselect" in cmds.listAttr(node): - connections = cmds.listConnections("{}.vray_mtl_mtlselect".format(node)) + connections = cmds.listConnections( + "{}.vray_mtl_mtlselect".format(node)) if connections: final_name += '_{}'.format(str(connections[0])) From 598297de935bd5cd151c711a3f081f828993465d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 16:26:57 +0100 Subject: [PATCH 128/279] audio may not be added to output based on tag "no-audio" in output definition --- pype/plugins/global/publish/extract_review.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pype/plugins/global/publish/extract_review.py b/pype/plugins/global/publish/extract_review.py index 857119176f..d08748209d 100644 --- a/pype/plugins/global/publish/extract_review.py +++ b/pype/plugins/global/publish/extract_review.py @@ -280,6 +280,15 @@ class ExtractReview(pyblish.api.InstancePlugin): handles_are_set = handle_start > 0 or handle_end > 0 + with_audio = True + if ( + # Check if has `no-audio` tag + "no-audio" in output_def["tags"] + # Check if instance has ny audio in data + or not instance.data.get("audio") + ): + with_audio = False + return { "fps": float(instance.data["fps"]), "frame_start": frame_start, @@ -295,6 +304,7 @@ class ExtractReview(pyblish.api.InstancePlugin): "resolution_height": instance.data.get("resolutionHeight"), "origin_repre": repre, "input_is_sequence": self.input_is_sequence(repre), + "with_audio": with_audio, "without_handles": without_handles, "handles_are_set": handles_are_set } @@ -389,7 +399,7 @@ class ExtractReview(pyblish.api.InstancePlugin): ffmpeg_output_args.append("-shortest") # Add audio arguments if there are any. Skipped when output are images. - if not temp_data["output_ext_is_image"]: + if not temp_data["output_ext_is_image"] and temp_data["with_audio"]: audio_in_args, audio_filters, audio_out_args = self.audio_args( instance, temp_data ) From b7480065c5c0b55dd015b79fd8c8faedfeefeb0a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 16:44:30 +0100 Subject: [PATCH 129/279] few minor fixes --- .../settings/settings/widgets/item_types.py | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 8b689ecd1a..cb7a310945 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1984,6 +1984,9 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): ) value_input.create_ui() + key_input = QtWidgets.QLineEdit(self) + key_input.setObjectName("DictKey") + wrapper_widget = None if self.labeled_items: wrapper_widget = ExpandingWidget("", self) @@ -1998,12 +2001,9 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): content_layout.addWidget(value_input) - key_input = QtWidgets.QLineEdit(self) - key_input.setObjectName("DictKey") - if self.labeled_items: def focused_out(event): QtWidgets.QLineEdit.focusOutEvent(key_input, event) - self._on_enter_press() + self._on_focus_lose() key_input.focusOutEvent = focused_out @@ -2034,7 +2034,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): if self.labeled_items: wrapper_widget.add_widget_after_label(key_input) wrapper_widget.add_widget_after_label(add_btn) - wrapper_widget.add_widget_after_label(edit_btn) + wrapper_widget.add_widget_before_label(edit_btn) else: layout.addWidget(add_btn, 0) @@ -2050,7 +2050,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): value_input.value_changed.connect(self._on_value_change) add_btn.clicked.connect(self.on_add_clicked) if edit_btn: - edit_btn.clicked.connect(self.on_edit_clicked) + edit_btn.clicked.connect(self.on_edit_pressed) if remove_btn: remove_btn.clicked.connect(self.on_remove_clicked) @@ -2092,6 +2092,14 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self.set_edit_mode(True) self.update_style() + def _on_focus_lose(self): + if ( + self.key_input.hasFocus() + or self.edit_btn.hasFocus() + ): + return + self._on_enter_press() + def _on_enter_press(self): if not self.labeled_items: return @@ -2156,8 +2164,11 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self.set_as_empty(False) self._parent.add_row(row=self.row() + 1, is_empty=True) - def on_edit_clicked(self): - self.set_edit_mode() + def on_edit_pressed(self): + if not self.key_input.isVisible(): + self.set_edit_mode() + else: + self.key_input.setFocus() def set_edit_mode(self, enabled=True): if self.is_invalid and not enabled: From 51f50cc5f4ef7e8411e137c1020ce1cfd0c27f7d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 16:45:54 +0100 Subject: [PATCH 130/279] implemented IconButton that just change color on hover --- .../settings/settings/widgets/widgets.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pype/tools/settings/settings/widgets/widgets.py b/pype/tools/settings/settings/widgets/widgets.py index 6135f8dcb2..1ff5ce2fdc 100644 --- a/pype/tools/settings/settings/widgets/widgets.py +++ b/pype/tools/settings/settings/widgets/widgets.py @@ -1,4 +1,23 @@ from Qt import QtWidgets, QtCore, QtGui +from avalon.vendor import qtawesome + + +class IconButton(QtWidgets.QPushButton): + def __init__(self, icon_name, color, hover_color, *args, **kwargs): + super(IconButton, self).__init__(*args, **kwargs) + + self.icon = qtawesome.icon(icon_name, color=color) + self.hover_icon = qtawesome.icon(icon_name, color=hover_color) + + self.setIcon(self.icon) + + def enterEvent(self, event): + self.setIcon(self.hover_icon) + super(IconButton, self).enterEvent(event) + + def leaveEvent(self, event): + self.setIcon(self.icon) + super(IconButton, self).leaveEvent(event) class NumberSpinBox(QtWidgets.QDoubleSpinBox): From 012e62c370aa4d3595110bf3725688ddea09a195 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 16:46:17 +0100 Subject: [PATCH 131/279] used IconButton for edit --- pype/tools/settings/settings/style/style.css | 5 +++++ pype/tools/settings/settings/widgets/item_types.py | 9 ++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/pype/tools/settings/settings/style/style.css b/pype/tools/settings/settings/style/style.css index dcc7a5effe..38fcd14448 100644 --- a/pype/tools/settings/settings/style/style.css +++ b/pype/tools/settings/settings/style/style.css @@ -97,6 +97,11 @@ QPushButton[btn-type="tool-item"]:hover { background-color: transparent; } +QPushButton[btn-type="tool-item-icon"] { + border: 0px solid #bfccd6; + background-color: transparent; +} + QPushButton[btn-type="expand-toggle"] { background: #1d272f; } diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index cb7a310945..e00f21a1e2 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2,6 +2,7 @@ import json import collections from Qt import QtWidgets, QtCore, QtGui from .widgets import ( + IconButton, ExpandingWidget, NumberSpinBox, PathInput, @@ -2021,10 +2022,12 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): edit_btn = None remove_btn = None if self.labeled_items: - edit_btn = QtWidgets.QPushButton("Edit") + edit_btn = IconButton( + "fa.edit", QtCore.Qt.lightGray, QtCore.Qt.white + ) edit_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - edit_btn.setProperty("btn-type", "tool-item") - edit_btn.setFixedSize(self._btn_size, self._btn_size) + edit_btn.setProperty("btn-type", "tool-item-icon") + edit_btn.setFixedHeight(self._btn_size) else: remove_btn = QtWidgets.QPushButton("-") remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) From 8ceeabc21bd5a34997ce5aa6260c7bee46ddda5e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 17:02:16 +0100 Subject: [PATCH 132/279] added label input --- .../settings/settings/widgets/item_types.py | 60 ++++++++++++++----- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index e00f21a1e2..5b92754752 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1988,8 +1988,11 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): key_input = QtWidgets.QLineEdit(self) key_input.setObjectName("DictKey") + key_label_input = None wrapper_widget = None if self.labeled_items: + key_label_input = QtWidgets.QLineEdit(self) + wrapper_widget = ExpandingWidget("", self) layout.addWidget(wrapper_widget) @@ -2002,11 +2005,16 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): content_layout.addWidget(value_input) - def focused_out(event): + def key_input_focused_out(event): QtWidgets.QLineEdit.focusOutEvent(key_input, event) self._on_focus_lose() - key_input.focusOutEvent = focused_out + def key_label_input_focused_out(event): + QtWidgets.QLineEdit.focusOutEvent(key_label_input, event) + self._on_focus_lose() + + key_input.focusOutEvent = key_input_focused_out + key_label_input.focusOutEvent = key_label_input_focused_out spacer_widget = None if not self.labeled_items: @@ -2035,9 +2043,10 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): remove_btn.setFixedSize(self._btn_size, self._btn_size) if self.labeled_items: - wrapper_widget.add_widget_after_label(key_input) - wrapper_widget.add_widget_after_label(add_btn) + wrapper_widget.add_widget_before_label(add_btn) wrapper_widget.add_widget_before_label(edit_btn) + wrapper_widget.add_widget_after_label(key_input) + wrapper_widget.add_widget_after_label(key_label_input) else: layout.addWidget(add_btn, 0) @@ -2050,7 +2059,12 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): key_input.textChanged.connect(self._on_key_change) key_input.returnPressed.connect(self._on_enter_press) + if key_label_input: + key_label_input.textChanged.connect(self._on_key_change) + key_label_input.returnPressed.connect(self._on_enter_press) + value_input.value_changed.connect(self._on_value_change) + add_btn.clicked.connect(self.on_add_clicked) if edit_btn: edit_btn.clicked.connect(self.on_edit_pressed) @@ -2058,6 +2072,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): remove_btn.clicked.connect(self.on_remove_clicked) self.key_input = key_input + self.key_label_input = key_label_input self.value_input = value_input self.wrapper_widget = wrapper_widget @@ -2091,14 +2106,18 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): return self._is_key_duplicated = duplicated - if duplicated and self.labeled_items: - self.set_edit_mode(True) + if self.labeled_items: + if duplicated: + self.set_edit_mode(True) + else: + self._on_focus_lose() self.update_style() def _on_focus_lose(self): if ( - self.key_input.hasFocus() - or self.edit_btn.hasFocus() + self.edit_btn.hasFocus() + or self.key_input.hasFocus() + or self.key_label_input.hasFocus() ): return self._on_enter_press() @@ -2112,11 +2131,15 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): else: self.set_edit_mode(False) + def _on_key_label_change(self): + self.update_key_label() + def _on_key_change(self): - value = self.key_input.text() if self.value_is_env_group: - self.value_input.env_group_key = value - self.change_key_label(value) + self.value_input.env_group_key = self.key_input.text() + + self.update_key_label() + self._on_value_change() def _on_value_change(self, item=None): @@ -2146,9 +2169,16 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): def is_group(self): return self._parent.is_group - def change_key_label(self, label): - if self.wrapper_widget: - self.wrapper_widget.label_widget.setText(label) + def update_key_label(self): + if not self.wrapper_widget: + return + key_value = self.key_input.text() + key_label_value = self.key_label_input.text() + if key_label_value: + label = "{} ({})".format(key_label_value, key_value) + else: + label = key_value + self.wrapper_widget.label_widget.setText(label) def on_add_clicked(self): if not self.labeled_items: @@ -2178,6 +2208,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): return self.wrapper_widget.label_widget.setVisible(not enabled) self.key_input.setVisible(enabled) + self.key_label_input.setVisible(enabled) if enabled: self.key_input.setFocus() @@ -2199,6 +2230,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): else: self.key_input.setVisible(is_empty) + self.key_label_input.setVisible(is_empty) self.edit_btn.setVisible(not is_empty) self.wrapper_widget.label_widget.setVisible(not is_empty) From 61ecb05a591f050366be770e4d6987c61d843322 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 17:10:26 +0100 Subject: [PATCH 133/279] adde remove btn on edit mode --- .../settings/settings/widgets/item_types.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 5b92754752..f76b9d2730 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2036,17 +2036,18 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): edit_btn.setFocusPolicy(QtCore.Qt.ClickFocus) edit_btn.setProperty("btn-type", "tool-item-icon") edit_btn.setFixedHeight(self._btn_size) - else: - remove_btn = QtWidgets.QPushButton("-") - remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - remove_btn.setProperty("btn-type", "tool-item") - remove_btn.setFixedSize(self._btn_size, self._btn_size) + + remove_btn = QtWidgets.QPushButton("-") + remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + remove_btn.setProperty("btn-type", "tool-item") + remove_btn.setFixedSize(self._btn_size, self._btn_size) if self.labeled_items: wrapper_widget.add_widget_before_label(add_btn) wrapper_widget.add_widget_before_label(edit_btn) wrapper_widget.add_widget_after_label(key_input) wrapper_widget.add_widget_after_label(key_label_input) + wrapper_widget.add_widget_after_label(remove_btn) else: layout.addWidget(add_btn, 0) @@ -2068,8 +2069,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): add_btn.clicked.connect(self.on_add_clicked) if edit_btn: edit_btn.clicked.connect(self.on_edit_pressed) - if remove_btn: - remove_btn.clicked.connect(self.on_remove_clicked) + remove_btn.clicked.connect(self.on_remove_clicked) self.key_input = key_input self.key_label_input = key_label_input @@ -2118,6 +2118,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self.edit_btn.hasFocus() or self.key_input.hasFocus() or self.key_label_input.hasFocus() + or self.remove_btn.hasFocus() ): return self._on_enter_press() @@ -2209,13 +2210,11 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self.wrapper_widget.label_widget.setVisible(not enabled) self.key_input.setVisible(enabled) self.key_label_input.setVisible(enabled) + self.remove_btn.setVisible(enabled) if enabled: self.key_input.setFocus() def on_remove_clicked(self): - self.remove_row() - - def remove_row(self): self._parent.remove_row(self) def set_as_empty(self, is_empty=True): @@ -2229,6 +2228,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self.spacer_widget.setVisible(is_empty) else: + self.remove_btn.setVisible(False) self.key_input.setVisible(is_empty) self.key_label_input.setVisible(is_empty) self.edit_btn.setVisible(not is_empty) From a24f2a15343e31f43fc42eabb899cd3f1d14ca61 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 17:17:23 +0100 Subject: [PATCH 134/279] minor styles fixes --- pype/tools/settings/settings/widgets/item_types.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index f76b9d2730..f2d42cdadf 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1997,6 +1997,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): layout.addWidget(wrapper_widget) content_widget = QtWidgets.QWidget(wrapper_widget) + content_widget.setObjectName("ContentWidget") content_layout = QtWidgets.QHBoxLayout(content_widget) content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) content_layout.setSpacing(5) @@ -2379,7 +2380,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): content_widget.setObjectName("ContentWidget") content_widget.setProperty("content_state", content_state) content_layout = QtWidgets.QVBoxLayout(content_widget) - content_layout.setContentsMargins(CHILD_OFFSET, 3, 0, bottom_margin) + content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, bottom_margin) if body_widget is None: main_layout.addWidget(content_widget) From 5fb35c8f5b0bbcedb827b51bee2756b932356d69 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 17:33:50 +0100 Subject: [PATCH 135/279] fix layout --- pype/tools/settings/settings/widgets/widgets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/widgets.py b/pype/tools/settings/settings/widgets/widgets.py index 1ff5ce2fdc..66afa565a3 100644 --- a/pype/tools/settings/settings/widgets/widgets.py +++ b/pype/tools/settings/settings/widgets/widgets.py @@ -127,7 +127,7 @@ class ExpandingWidget(QtWidgets.QWidget): label_widget.setObjectName("DictLabel") before_label_widget = QtWidgets.QWidget(side_line_widget) - before_label_layout = QtWidgets.QVBoxLayout(before_label_widget) + before_label_layout = QtWidgets.QHBoxLayout(before_label_widget) before_label_layout.setContentsMargins(0, 0, 0, 0) after_label_widget = QtWidgets.QWidget(side_line_widget) From d49c683eec36e258e6a23cd9f59a3493bad56cd3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 17:35:27 +0100 Subject: [PATCH 136/279] added storing label value in metadata --- .../settings/settings/widgets/item_types.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index f2d42cdadf..ee4bbde5ca 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2281,6 +2281,9 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): def row(self): return self._parent.input_fields.index(self) + def label_value(self): + return self.key_label_input.text() + def item_value(self): key = self.key_input.text() value = self.value_input.item_value() @@ -2503,12 +2506,29 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): output.update(item.item_value()) return output + def item_value_with_metadata(self): + output = {} + labels_by_key = {} + for item in self.input_fields: + labels_by_key[item.key_value()] = item.label_value() + output.update(item.config_value()) + + output[METADATA_KEY] = { + "dynamic_key_label": labels_by_key + } + return output + def item_value(self): output = {} for item in self.input_fields: output.update(item.config_value()) return output + def config_value(self): + if not self.labeled_items: + return super(ModifiableDict, self).config_value() + return {self.key: self.item_value_with_metadata()} + def add_row(self, row=None, key=None, value=None, is_empty=False): # Create new item item_widget = ModifiableDictItem( From 500df0a052e30b974ac003c5e75c6112efb5fd73 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 17:49:35 +0100 Subject: [PATCH 137/279] little bit safer metadata storing --- .../settings/settings/widgets/item_types.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 3ffba4893d..d2efb703f1 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1342,10 +1342,10 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): def config_value(self): value = self.item_value() if self.is_environ: - value[METADATA_KEY] = { - "environments": { - self.env_group_key: list(value.keys()) - } + if METADATA_KEY not in value: + value[METADATA_KEY] = {} + value[METADATA_KEY]["environments"] = { + self.env_group_key: list(value.keys()) } return {self.key: value} @@ -3617,7 +3617,9 @@ class DictFormWidget(QtWidgets.QWidget, SettingObject): if is_group: groups.extend(value.keys()) if groups: - values[METADATA_KEY] = {"groups": groups} + if METADATA_KEY not in values: + values[METADATA_KEY] = {} + values[METADATA_KEY]["groups"] = groups return values, self.is_group def overrides(self): @@ -3633,7 +3635,9 @@ class DictFormWidget(QtWidgets.QWidget, SettingObject): if is_group: groups.extend(value.keys()) if groups: - values[METADATA_KEY] = {"groups": groups} + if METADATA_KEY not in values: + values[METADATA_KEY] = {} + values[METADATA_KEY]["groups"] = groups return values, self.is_group From a4a684f32f5764a46598ed8530994892a94f3266 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 17:50:02 +0100 Subject: [PATCH 138/279] unified method for getting modifiable dict item value with metadata --- .../settings/settings/widgets/item_types.py | 40 ++++++++++--------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index d2efb703f1..db62beddf8 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2506,15 +2506,28 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): return output def item_value_with_metadata(self): - output = {} - labels_by_key = {} - for item in self.input_fields: - labels_by_key[item.key_value()] = item.label_value() - output.update(item.config_value()) + metadata = {} + if not self.labeled_items: + output = self.item_value() + + else: + output = {} + labels_by_key = {} + for item in self.input_fields: + labels_by_key[item.key_value()] = item.label_value() + output.update(item.config_value()) + metadata["dynamic_key_label"] = labels_by_key + + if self.value_is_env_group: + for key, value in tuple(output.items()): + metadata["environments"] = {key: list(value.keys())} + output[key] = value + + if metadata: + if METADATA_KEY not in output: + output[METADATA_KEY] = {} + output[METADATA_KEY].update(metadata) - output[METADATA_KEY] = { - "dynamic_key_label": labels_by_key - } return output def item_value(self): @@ -2524,16 +2537,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): return output def config_value(self): - output = self.item_value() - if self.value_is_env_group: - for key, value in tuple(output.items()): - value[METADATA_KEY] = { - "environments": { - key: list(value.keys()) - } - } - output[key] = value - return {self.key: output} + return {self.key: self.item_value_with_metadata()} def add_row(self, row=None, key=None, value=None, is_empty=False): # Create new item From b79d8b65ffc96e106fe35178c76f9e9616713fef Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 17:55:10 +0100 Subject: [PATCH 139/279] fix anatomy creation --- pype/tools/settings/settings/widgets/anatomy_types.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pype/tools/settings/settings/widgets/anatomy_types.py b/pype/tools/settings/settings/widgets/anatomy_types.py index 680db140a6..83183e7943 100644 --- a/pype/tools/settings/settings/widgets/anatomy_types.py +++ b/pype/tools/settings/settings/widgets/anatomy_types.py @@ -67,6 +67,7 @@ class AnatomyWidget(QtWidgets.QWidget, SettingObject): self.root_widget = RootsWidget(roots_input_data, self) self.templates_widget = TemplatesWidget(templates_input_data, self) self.imageio_widget = DictWidget(imageio_input_data, self) + self.imageio_widget.create_ui() self.setAttribute(QtCore.Qt.WA_StyledBackground) From 9de325987a1f7073ef51dc5d13c449711c8a351f Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 27 Nov 2020 17:57:58 +0100 Subject: [PATCH 140/279] Fix frame start, fix frame end --- .../stubs/aftereffects_server_stub.py | 2 +- .../plugins/aftereffects/publish/collect_render.py | 8 +++----- .../aftereffects/publish/extract_save_scene.py | 14 ++++++++++++++ .../publish/submit_aftereffects_deadline.py | 9 ++++----- pype/plugins/global/publish/submit_publish_job.py | 7 +++++++ 5 files changed, 29 insertions(+), 11 deletions(-) create mode 100644 pype/plugins/aftereffects/publish/extract_save_scene.py diff --git a/pype/modules/websocket_server/stubs/aftereffects_server_stub.py b/pype/modules/websocket_server/stubs/aftereffects_server_stub.py index e47aaee471..0b8c54e884 100644 --- a/pype/modules/websocket_server/stubs/aftereffects_server_stub.py +++ b/pype/modules/websocket_server/stubs/aftereffects_server_stub.py @@ -321,7 +321,7 @@ class AfterEffectsServerStub(): if records: return records.pop() - log.debug("Couldn't get render queue info") + log.debug("Render queue needs to have file extension in 'Output to'") def get_audio_url(self, item_id): """ Get audio layer absolute url for comp diff --git a/pype/plugins/aftereffects/publish/collect_render.py b/pype/plugins/aftereffects/publish/collect_render.py index f053eb7ce3..fbe392d52b 100644 --- a/pype/plugins/aftereffects/publish/collect_render.py +++ b/pype/plugins/aftereffects/publish/collect_render.py @@ -40,13 +40,11 @@ class CollectAERender(abstract_collect_render.AbstractCollectRender): continue work_area_info = aftereffects.stub().get_work_area(int(item_id)) - frameStart = round(float(work_area_info.workAreaStart) * - float(work_area_info.frameRate)) + frameStart = work_area_info.workAreaStart - frameEnd = round(float(work_area_info.workAreaStart) * - float(work_area_info.frameRate) + + frameEnd = round(work_area_info.workAreaStart + float(work_area_info.workAreaDuration) * - float(work_area_info.frameRate)) + float(work_area_info.frameRate)) - 1 if inst["family"] == "render" and inst["active"]: instance = AERenderInstance( diff --git a/pype/plugins/aftereffects/publish/extract_save_scene.py b/pype/plugins/aftereffects/publish/extract_save_scene.py new file mode 100644 index 0000000000..e19065d086 --- /dev/null +++ b/pype/plugins/aftereffects/publish/extract_save_scene.py @@ -0,0 +1,14 @@ +import pype.api +from avalon import aftereffects + + +class ExtractSaveScene(pype.api.Extractor): + """Save scene before extraction.""" + + order = pype.api.Extractor.order - 0.49 + label = "Extract Save Scene" + hosts = ["aftereffects"] + families = ["workfile"] + + def process(self, instance): + aftereffects.stub().save() diff --git a/pype/plugins/aftereffects/publish/submit_aftereffects_deadline.py b/pype/plugins/aftereffects/publish/submit_aftereffects_deadline.py index 8bb42a0239..d5f2747be7 100644 --- a/pype/plugins/aftereffects/publish/submit_aftereffects_deadline.py +++ b/pype/plugins/aftereffects/publish/submit_aftereffects_deadline.py @@ -29,6 +29,8 @@ class AfterEffectsSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline families = ["render.farm"] # cannot be "render' as that is integrated use_published = False + chunk_size = 1000000 + def get_job_info(self): dln_job_info = DeadlineJobInfo(Plugin="AfterEffects") @@ -45,8 +47,7 @@ class AfterEffectsSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline self._instance.data["frameEnd"]) dln_job_info.Frames = frame_range - if len(self._instance.data["expectedFiles"]) == 1: - dln_job_info.ChunkSize = 1000000 + dln_job_info.ChunkSize = self.chunk_size dln_job_info.OutputFilename = \ os.path.basename(self._instance.data["expectedFiles"][0]) @@ -97,10 +98,8 @@ class AfterEffectsSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline render_path = os.path.join(render_dir, '{}.{}.{}'.format(arr[0], hashed, arr[2])) - deadline_plugin_info.MultiProcess = True - else: - deadline_plugin_info.MultiProcess = False + deadline_plugin_info.MultiProcess = True deadline_plugin_info.Comp = self._instance.data["comp_name"] deadline_plugin_info.Version = "17.5" deadline_plugin_info.SceneFile = script_path diff --git a/pype/plugins/global/publish/submit_publish_job.py b/pype/plugins/global/publish/submit_publish_job.py index 256bf01665..b8bf240c06 100644 --- a/pype/plugins/global/publish/submit_publish_job.py +++ b/pype/plugins/global/publish/submit_publish_job.py @@ -600,6 +600,13 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin): "files": os.path.basename(remainder), "stagingDir": os.path.dirname(remainder), } + if "render" in instance.get("families"): + rep.update({ + "fps": instance.get("fps"), + "tags": ["review"] + }) + self._solve_families(instance, True) + if remainder in bake_render_path: rep.update({ "fps": instance.get("fps"), From 3e23b9ab1b78f2c842505bcb3a7b09b9be2e535a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 18:12:57 +0100 Subject: [PATCH 141/279] fixed env group metadata storing --- .../settings/settings/widgets/item_types.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index db62beddf8..8bfb1dd091 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2506,7 +2506,6 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): return output def item_value_with_metadata(self): - metadata = {} if not self.labeled_items: output = self.item_value() @@ -2516,18 +2515,18 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): for item in self.input_fields: labels_by_key[item.key_value()] = item.label_value() output.update(item.config_value()) - metadata["dynamic_key_label"] = labels_by_key + if METADATA_KEY not in output: + output[METADATA_KEY] = {} + output[METADATA_KEY]["dynamic_key_label"] = labels_by_key if self.value_is_env_group: for key, value in tuple(output.items()): - metadata["environments"] = {key: list(value.keys())} + if METADATA_KEY not in value: + value[METADATA_KEY] = {} + value[METADATA_KEY]["environments"] = { + key: list(value.keys()) + } output[key] = value - - if metadata: - if METADATA_KEY not in output: - output[METADATA_KEY] = {} - output[METADATA_KEY].update(metadata) - return output def item_value(self): From 6903865976f404df6dbde84c13261cdaebb0eb38 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 18:34:26 +0100 Subject: [PATCH 142/279] fixed metadata --- .../settings/settings/widgets/item_types.py | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 8bfb1dd091..5a02497f71 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1344,8 +1344,14 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): if self.is_environ: if METADATA_KEY not in value: value[METADATA_KEY] = {} + + env_keys = [] + for key in value.keys(): + if key is not METADATA_KEY: + env_keys.append(key) + value[METADATA_KEY]["environments"] = { - self.env_group_key: list(value.keys()) + self.env_group_key: env_keys } return {self.key: value} @@ -2520,13 +2526,17 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): output[METADATA_KEY]["dynamic_key_label"] = labels_by_key if self.value_is_env_group: - for key, value in tuple(output.items()): + for env_group_key, value in tuple(output.items()): + env_keys = [] + for key in value.keys(): + if key is not METADATA_KEY: + env_keys.append(key) + if METADATA_KEY not in value: value[METADATA_KEY] = {} - value[METADATA_KEY]["environments"] = { - key: list(value.keys()) - } - output[key] = value + + value[METADATA_KEY]["environments"] = {env_group_key: env_keys} + output[env_group_key] = value return output def item_value(self): From 0b18f1cce3238665bc7f97ffd8de550eed23ac90 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 19:01:25 +0100 Subject: [PATCH 143/279] fixed few issues of loaded data --- pype/settings/lib.py | 2 ++ pype/tools/settings/settings/widgets/item_types.py | 6 +++++- pype/tools/settings/settings/widgets/lib.py | 13 ++++++++++++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index a50d7793b5..ebd0d86df4 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -9,6 +9,8 @@ log = logging.getLogger(__name__) M_OVERRIDEN_KEY = "__overriden_keys__" # Metadata key for storing information about environments M_ENVIRONMENT_KEY = "__environment_keys__" +# Metadata key for storing dynamic created labels +M_DYNAMIC_KEY_LABEL = "__dynamic_keys_labels__" # NOTE key popping not implemented yet M_POP_KEY = "__pop_key__" diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 5a02497f71..ca4d28ccbc 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2034,7 +2034,6 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): add_btn.setFixedSize(self._btn_size, self._btn_size) edit_btn = None - remove_btn = None if self.labeled_items: edit_btn = IconButton( "fa.edit", QtCore.Qt.lightGray, QtCore.Qt.white @@ -2049,6 +2048,9 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): remove_btn.setFixedSize(self._btn_size, self._btn_size) if self.labeled_items: + add_btn.setVisible(False) + remove_btn.setVisible(False) + wrapper_widget.add_widget_before_label(add_btn) wrapper_widget.add_widget_before_label(edit_btn) wrapper_widget.add_widget_after_label(key_input) @@ -2422,6 +2424,8 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): previous_inputs = tuple(self.input_fields) for item_key, item_value in value.items(): self.add_row(key=item_key, value=item_value) + if self.labeled_items: + self.add_row(is_empty=True) for input_field in previous_inputs: self.remove_row(input_field) diff --git a/pype/tools/settings/settings/widgets/lib.py b/pype/tools/settings/settings/widgets/lib.py index f112a6e975..9a6331009b 100644 --- a/pype/tools/settings/settings/widgets/lib.py +++ b/pype/tools/settings/settings/widgets/lib.py @@ -2,7 +2,11 @@ import os import re import json import copy -from pype.settings.lib import M_OVERRIDEN_KEY, M_ENVIRONMENT_KEY +from pype.settings.lib import ( + M_OVERRIDEN_KEY, + M_ENVIRONMENT_KEY, + M_DYNAMIC_KEY_LABEL +) from queue import Queue @@ -35,6 +39,8 @@ def convert_gui_data_with_metadata(data, ignored_keys=None): if key == "environments": output[M_ENVIRONMENT_KEY] = value + elif key == "dynamic_key_label": + output[M_DYNAMIC_KEY_LABEL] = value else: raise KeyError("Unknown metadata key \"{}\"".format(key)) @@ -51,6 +57,11 @@ def convert_data_to_gui_data(data, first=True): if M_ENVIRONMENT_KEY in data: data.pop(M_ENVIRONMENT_KEY) + if M_DYNAMIC_KEY_LABEL in data: + if METADATA_KEY not in data: + data[METADATA_KEY] = {} + data[METADATA_KEY]["dynamic_key_label"] = data.pop(M_DYNAMIC_KEY_LABEL) + for key, value in data.items(): output[key] = convert_data_to_gui_data(value, False) From 295f89a730deada88fce45bf8ad37b9f2ec0daeb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 19:02:56 +0100 Subject: [PATCH 144/279] add_row can enter label --- .../settings/settings/widgets/item_types.py | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index ca4d28ccbc..11c8fdeaa9 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2155,19 +2155,25 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self.update_style() self.value_changed.emit(self) - def update_default_values(self, key, value): + def update_default_values(self, key, label, value): self.origin_key = key self.key_input.setText(key) + if self.key_label_input: + self.key_label_input.setText(label or "") self.value_input.update_default_values(value) - def update_studio_values(self, key, value): + def update_studio_values(self, key, label, value): self.origin_key = key self.key_input.setText(key) + if self.key_label_input: + self.key_label_input.setText(label or "") self.value_input.update_studio_values(value) - def apply_overrides(self, key, value): + def apply_overrides(self, key, label, value): self.origin_key = key self.key_input.setText(key) + if self.key_label_input: + self.key_label_input.setText(label or "") self.value_input.apply_overrides(value) @property @@ -2421,9 +2427,14 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): def set_value(self, value): self.validate_value(value) + metadata = value.pop(METADATA_KEY, {}) + dynamic_key_labels = metadata.get("dynamic_key_label") or {} + previous_inputs = tuple(self.input_fields) for item_key, item_value in value.items(): - self.add_row(key=item_key, value=item_value) + label = dynamic_key_labels.get(item_key) + self.add_row(key=item_key, label=label, value=item_value) + if self.labeled_items: self.add_row(is_empty=True) @@ -2552,7 +2563,9 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): def config_value(self): return {self.key: self.item_value_with_metadata()} - def add_row(self, row=None, key=None, value=None, is_empty=False): + def add_row( + self, row=None, key=None, label=None, value=None, is_empty=False + ): # Create new item item_widget = ModifiableDictItem( self.item_schema, self, self.content_widget @@ -2593,11 +2606,11 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): # else (when add button clicked) trigger `_on_value_change` if value is not None and key is not None: if not self._has_studio_override: - item_widget.update_default_values(key, value) + item_widget.update_default_values(key, label, value) elif self._is_overriden: - item_widget.apply_overrides(key, value) + item_widget.apply_overrides(key, label, value) else: - item_widget.update_studio_values(key, value) + item_widget.update_studio_values(key, label, value) self.hierarchical_style_update() else: self._on_value_change() From 4bceafe3e569bab0820702e15e35be62f0de1d6a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 19:04:50 +0100 Subject: [PATCH 145/279] better initial state of modifiable dict item --- pype/tools/settings/settings/widgets/item_types.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 11c8fdeaa9..1c70b67bdb 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2048,9 +2048,6 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): remove_btn.setFixedSize(self._btn_size, self._btn_size) if self.labeled_items: - add_btn.setVisible(False) - remove_btn.setVisible(False) - wrapper_widget.add_widget_before_label(add_btn) wrapper_widget.add_widget_before_label(edit_btn) wrapper_widget.add_widget_after_label(key_input) @@ -2091,6 +2088,8 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self.edit_btn = edit_btn self.remove_btn = remove_btn + self.set_as_empty(self._is_empty) + @property def labeled_items(self): return self._parent.labeled_items From dc353e03a805fcdf253b24fc2bb1f3dc76b1cfc2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 19:08:57 +0100 Subject: [PATCH 146/279] do not pop metadata key, just skip it --- pype/tools/settings/settings/widgets/item_types.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 1c70b67bdb..faaf9de4bb 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2426,11 +2426,12 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): def set_value(self, value): self.validate_value(value) - metadata = value.pop(METADATA_KEY, {}) + metadata = value.get(METADATA_KEY, {}) dynamic_key_labels = metadata.get("dynamic_key_label") or {} - previous_inputs = tuple(self.input_fields) for item_key, item_value in value.items(): + if item_key is METADATA_KEY: + continue label = dynamic_key_labels.get(item_key) self.add_row(key=item_key, label=label, value=item_value) From 6cd6d9ef9036adb9aa0dab1fa043193432eb9f5d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 19:40:10 +0100 Subject: [PATCH 147/279] proper stylesheets and key label modifications --- .../settings/settings/widgets/item_types.py | 81 ++++++++++++++++--- 1 file changed, 70 insertions(+), 11 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index faaf9de4bb..1eadd843a3 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1973,6 +1973,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self._is_key_duplicated = False self.origin_key = NOT_SET + self.origin_key_label = NOT_SET if self.labeled_items: layout = QtWidgets.QVBoxLayout(self) @@ -2090,6 +2091,23 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self.set_as_empty(self._is_empty) + def _style_state(self): + if self.as_widget: + state = self.style_state( + False, + self._is_invalid, + False, + self.is_modified + ) + else: + state = self.style_state( + self.has_studio_override, + self.is_invalid, + self.is_overriden, + self.is_modified + ) + return state + @property def labeled_items(self): return self._parent.labeled_items @@ -2158,21 +2176,27 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self.origin_key = key self.key_input.setText(key) if self.key_label_input: - self.key_label_input.setText(label or "") + label = label or "" + self.origin_key_label = label + self.key_label_input.setText(label) self.value_input.update_default_values(value) def update_studio_values(self, key, label, value): self.origin_key = key self.key_input.setText(key) if self.key_label_input: - self.key_label_input.setText(label or "") + label = label or "" + self.origin_key_label = label + self.key_label_input.setText(label) self.value_input.update_studio_values(value) def apply_overrides(self, key, label, value): self.origin_key = key self.key_input.setText(key) if self.key_label_input: - self.key_label_input.setText(label or "") + label = label or "" + self.origin_key_label = label + self.key_label_input.setText(label) self.value_input.apply_overrides(value) @property @@ -2260,6 +2284,9 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): def is_key_modified(self): return self.key_value() != self.origin_key + def is_key_label_modified(self): + return self.key_label_value() != self.origin_key_label + def is_value_modified(self): return self.value_input.is_modified @@ -2267,7 +2294,11 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): def is_modified(self): if self._is_empty: return False - return self.is_value_modified() or self.is_key_modified() + return ( + self.is_value_modified() + or self.is_key_modified() + or self.is_key_label_modified() + ) def hierarchical_style_update(self): self.value_input.hierarchical_style_update() @@ -2280,21 +2311,49 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): return self.is_key_invalid() or self.value_input.is_invalid def update_style(self): - state = "" + key_input_state = "" if not self._is_empty: if self.is_key_invalid(): - state = "invalid" + key_input_state = "invalid" elif self.is_key_modified(): - state = "modified" + key_input_state = "modified" - self.key_input.setProperty("state", state) + self.key_input.setProperty("state", key_input_state) self.key_input.style().polish(self.key_input) + if not self.wrapper_widget: + return + + state = self._style_state() + + if self._state == state: + return + + self._state = state + + if self.wrapper_widget.label_widget: + self.wrapper_widget.label_widget.setProperty("state", state) + self.wrapper_widget.label_widget.style().polish( + self.wrapper_widget.label_widget + ) + + if state: + child_state = "child-{}".format(state) + else: + child_state = "" + + self.wrapper_widget.side_line_widget.setProperty("state", child_state) + self.wrapper_widget.side_line_widget.style().polish( + self.wrapper_widget.side_line_widget + ) + def row(self): return self._parent.input_fields.index(self) - def label_value(self): - return self.key_label_input.text() + def key_label_value(self): + if self.labeled_items: + return self.key_label_input.text() + return NOT_SET def item_value(self): key = self.key_input.text() @@ -2534,7 +2593,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): output = {} labels_by_key = {} for item in self.input_fields: - labels_by_key[item.key_value()] = item.label_value() + labels_by_key[item.key_value()] = item.key_label_value() output.update(item.config_value()) if METADATA_KEY not in output: output[METADATA_KEY] = {} From ccc758cdced307c7eaa134099fca74e5e94a78ea Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 27 Nov 2020 19:44:22 +0100 Subject: [PATCH 148/279] added labels to inputs --- pype/tools/settings/settings/widgets/item_types.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 1eadd843a3..d4942e04d2 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2048,10 +2048,16 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): remove_btn.setProperty("btn-type", "tool-item") remove_btn.setFixedSize(self._btn_size, self._btn_size) + key_input_label_widget = None + key_label_input_label_widget = None if self.labeled_items: + key_input_label_widget = QtWidgets.QLabel("Key:") + key_label_input_label_widget = QtWidgets.QLabel("Label:") wrapper_widget.add_widget_before_label(add_btn) wrapper_widget.add_widget_before_label(edit_btn) + wrapper_widget.add_widget_after_label(key_input_label_widget) wrapper_widget.add_widget_after_label(key_input) + wrapper_widget.add_widget_after_label(key_label_input_label_widget) wrapper_widget.add_widget_after_label(key_label_input) wrapper_widget.add_widget_after_label(remove_btn) @@ -2078,9 +2084,10 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): remove_btn.clicked.connect(self.on_remove_clicked) self.key_input = key_input + self.key_input_label_widget = key_input_label_widget self.key_label_input = key_label_input + self.key_label_input_label_widget = key_label_input_label_widget self.value_input = value_input - self.wrapper_widget = wrapper_widget self.spacer_widget = spacer_widget @@ -2245,7 +2252,9 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): if self.is_invalid and not enabled: return self.wrapper_widget.label_widget.setVisible(not enabled) + self.key_label_input_label_widget.setVisible(enabled) self.key_input.setVisible(enabled) + self.key_input_label_widget.setVisible(enabled) self.key_label_input.setVisible(enabled) self.remove_btn.setVisible(enabled) if enabled: @@ -2266,7 +2275,9 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): else: self.remove_btn.setVisible(False) + self.key_input_label_widget.setVisible(is_empty) self.key_input.setVisible(is_empty) + self.key_label_input_label_widget.setVisible(is_empty) self.key_label_input.setVisible(is_empty) self.edit_btn.setVisible(not is_empty) From 6e9fc1c13e6760a39bcc445b1be5fa64b52a241f Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 27 Nov 2020 20:37:29 +0100 Subject: [PATCH 149/279] Fix activate 'use_published' --- pype/lib/abstract_submit_deadline.py | 4 +++- .../aftereffects/publish/submit_aftereffects_deadline.py | 7 +++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/pype/lib/abstract_submit_deadline.py b/pype/lib/abstract_submit_deadline.py index 09916523a4..170e4908b7 100644 --- a/pype/lib/abstract_submit_deadline.py +++ b/pype/lib/abstract_submit_deadline.py @@ -520,6 +520,7 @@ class AbstractSubmitDeadline(pyblish.api.InstancePlugin): f.replace(orig_scene, new_scene) ) new_exp[aov] = replaced_files + # [] might be too much here, TODO self._instance.data["expectedFiles"] = [new_exp] else: new_exp = [] @@ -527,7 +528,8 @@ class AbstractSubmitDeadline(pyblish.api.InstancePlugin): new_exp.append( f.replace(orig_scene, new_scene) ) - self._instance.data["expectedFiles"] = [new_exp] + self._instance.data["expectedFiles"] = new_exp + self.log.info("Scene name was switched {} -> {}".format( orig_scene, new_scene )) diff --git a/pype/plugins/aftereffects/publish/submit_aftereffects_deadline.py b/pype/plugins/aftereffects/publish/submit_aftereffects_deadline.py index d5f2747be7..9414bdd39d 100644 --- a/pype/plugins/aftereffects/publish/submit_aftereffects_deadline.py +++ b/pype/plugins/aftereffects/publish/submit_aftereffects_deadline.py @@ -24,10 +24,10 @@ class DeadlinePluginInfo(): class AfterEffectsSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): label = "Submit AE to Deadline" - order = pyblish.api.IntegratorOrder + order = pyblish.api.IntegratorOrder + 0.1 hosts = ["aftereffects"] families = ["render.farm"] # cannot be "render' as that is integrated - use_published = False + use_published = True chunk_size = 1000000 @@ -48,7 +48,6 @@ class AfterEffectsSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline dln_job_info.Frames = frame_range dln_job_info.ChunkSize = self.chunk_size - dln_job_info.OutputFilename = \ os.path.basename(self._instance.data["expectedFiles"][0]) dln_job_info.OutputDirectory = \ @@ -102,7 +101,7 @@ class AfterEffectsSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline deadline_plugin_info.MultiProcess = True deadline_plugin_info.Comp = self._instance.data["comp_name"] deadline_plugin_info.Version = "17.5" - deadline_plugin_info.SceneFile = script_path + deadline_plugin_info.SceneFile = self.scene_path deadline_plugin_info.Output = render_path.replace("\\", "/") return attr.asdict(deadline_plugin_info) From 019562e5ace866850d6299041e2ef88e0fda2dad Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Fri, 27 Nov 2020 21:41:49 +0100 Subject: [PATCH 150/279] integrate hierarchy ftrack temporary python 2 fix --- .../publish/integrate_hierarchy_ftrack.py | 51 +-- .../publish/integrate_hierarchy_ftrack_SP.py | 331 ++++++++++++++++++ 2 files changed, 341 insertions(+), 41 deletions(-) create mode 100644 pype/plugins/ftrack/publish/integrate_hierarchy_ftrack_SP.py diff --git a/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py index ef8ee9a216..a1377cc771 100644 --- a/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py +++ b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py @@ -1,13 +1,12 @@ import sys import six -import collections import pyblish.api from avalon import io -from pype.modules.ftrack.lib.avalon_sync import ( - CUST_ATTR_AUTO_SYNC, - get_pype_attr -) +try: + from pype.modules.ftrack.lib.avalon_sync import CUST_ATTR_AUTO_SYNC +except Exception: + CUST_ATTR_AUTO_SYNC = "avalon_auto_sync" class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): @@ -37,6 +36,7 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): order = pyblish.api.IntegratorOrder - 0.04 label = 'Integrate Hierarchy To Ftrack' families = ["shot"] + hosts = ["hiero"] optional = False def process(self, context): @@ -74,15 +74,6 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): self.auto_sync_on(project) def import_to_ftrack(self, input_data, parent=None): - # Prequery hiearchical custom attributes - hier_custom_attributes = get_pype_attr(self.session)[1] - hier_attr_by_key = { - attr["key"]: attr - for attr in hier_custom_attributes - } - # Get ftrack api module (as they are different per python version) - ftrack_api = self.context.data["ftrackPythonModule"] - for entity_name in input_data: entity_data = input_data[entity_name] entity_type = entity_data['entity_type'] @@ -125,34 +116,12 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): i for i in self.context if i.data['asset'] in entity['name'] ] for key in custom_attributes: - hier_attr = hier_attr_by_key.get(key) - # Use simple method if key is not hierarchical - if not hier_attr: - assert (key in entity['custom_attributes']), ( - 'Missing custom attribute key: `{0}` in attrs: ' - '`{1}`'.format(key, entity['custom_attributes'].keys()) - ) + assert (key in entity['custom_attributes']), ( + 'Missing custom attribute key: `{0}` in attrs: ' + '`{1}`'.format(key, entity['custom_attributes'].keys()) + ) - entity['custom_attributes'][key] = custom_attributes[key] - - else: - # Use ftrack operations method to set hiearchical - # attribute value. - # - this is because there may be non hiearchical custom - # attributes with different properties - entity_key = collections.OrderedDict({ - "configuration_id": hier_attr["id"], - "entity_id": entity["id"] - }) - self.session.recorded_operations.push( - ftrack_api.operation.UpdateEntityOperation( - "ContextCustomAttributeValue", - entity_key, - "value", - ftrack_api.symbol.NOT_SET, - custom_attributes[key] - ) - ) + entity['custom_attributes'][key] = custom_attributes[key] for instance in instances: instance.data['ftrackEntity'] = entity diff --git a/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack_SP.py b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack_SP.py new file mode 100644 index 0000000000..ac606ed27d --- /dev/null +++ b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack_SP.py @@ -0,0 +1,331 @@ +import sys +import six +import collections +import pyblish.api +from avalon import io + +from pype.modules.ftrack.lib.avalon_sync import ( + CUST_ATTR_AUTO_SYNC, + get_pype_attr +) + + +class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): + """ + Create entities in ftrack based on collected data from premiere + Example of entry data: + { + "ProjectXS": { + "entity_type": "Project", + "custom_attributes": { + "fps": 24,... + }, + "tasks": [ + "Compositing", + "Lighting",... *task must exist as task type in project schema* + ], + "childs": { + "sq01": { + "entity_type": "Sequence", + ... + } + } + } + } + """ + + order = pyblish.api.IntegratorOrder - 0.04 + label = 'Integrate Hierarchy To Ftrack' + families = ["shot"] + hosts = ["standalonepublisher"] + optional = False + + def process(self, context): + self.context = context + if "hierarchyContext" not in self.context.data: + return + + hierarchy_context = self.context.data["hierarchyContext"] + + self.session = self.context.data["ftrackSession"] + project_name = self.context.data["projectEntity"]["name"] + query = 'Project where full_name is "{}"'.format(project_name) + project = self.session.query(query).one() + auto_sync_state = project[ + "custom_attributes"][CUST_ATTR_AUTO_SYNC] + + if not io.Session: + io.install() + + self.ft_project = None + + input_data = hierarchy_context + + # disable termporarily ftrack project's autosyncing + if auto_sync_state: + self.auto_sync_off(project) + + try: + # import ftrack hierarchy + self.import_to_ftrack(input_data) + except Exception: + raise + finally: + if auto_sync_state: + self.auto_sync_on(project) + + def import_to_ftrack(self, input_data, parent=None): + # Prequery hiearchical custom attributes + hier_custom_attributes = get_pype_attr(self.session)[1] + hier_attr_by_key = { + attr["key"]: attr + for attr in hier_custom_attributes + } + # Get ftrack api module (as they are different per python version) + ftrack_api = self.context.data["ftrackPythonModule"] + + for entity_name in input_data: + entity_data = input_data[entity_name] + entity_type = entity_data['entity_type'] + self.log.debug(entity_data) + self.log.debug(entity_type) + + if entity_type.lower() == 'project': + query = 'Project where full_name is "{}"'.format(entity_name) + entity = self.session.query(query).one() + self.ft_project = entity + self.task_types = self.get_all_task_types(entity) + + elif self.ft_project is None or parent is None: + raise AssertionError( + "Collected items are not in right order!" + ) + + # try to find if entity already exists + else: + query = ( + 'TypedContext where name is "{0}" and ' + 'project_id is "{1}"' + ).format(entity_name, self.ft_project["id"]) + try: + entity = self.session.query(query).one() + except Exception: + entity = None + + # Create entity if not exists + if entity is None: + entity = self.create_entity( + name=entity_name, + type=entity_type, + parent=parent + ) + # self.log.info('entity: {}'.format(dict(entity))) + # CUSTOM ATTRIBUTES + custom_attributes = entity_data.get('custom_attributes', []) + instances = [ + i for i in self.context if i.data['asset'] in entity['name'] + ] + for key in custom_attributes: + hier_attr = hier_attr_by_key.get(key) + # Use simple method if key is not hierarchical + if not hier_attr: + assert (key in entity['custom_attributes']), ( + 'Missing custom attribute key: `{0}` in attrs: ' + '`{1}`'.format(key, entity['custom_attributes'].keys()) + ) + + entity['custom_attributes'][key] = custom_attributes[key] + + else: + # Use ftrack operations method to set hiearchical + # attribute value. + # - this is because there may be non hiearchical custom + # attributes with different properties + entity_key = collections.OrderedDict({ + "configuration_id": hier_attr["id"], + "entity_id": entity["id"] + }) + self.session.recorded_operations.push( + ftrack_api.operation.UpdateEntityOperation( + "ContextCustomAttributeValue", + entity_key, + "value", + ftrack_api.symbol.NOT_SET, + custom_attributes[key] + ) + ) + + for instance in instances: + instance.data['ftrackEntity'] = entity + + try: + self.session.commit() + except Exception: + tp, value, tb = sys.exc_info() + self.session.rollback() + self.session._configure_locations() + six.reraise(tp, value, tb) + + # TASKS + tasks = entity_data.get('tasks', []) + existing_tasks = [] + tasks_to_create = [] + for child in entity['children']: + if child.entity_type.lower() == 'task': + existing_tasks.append(child['name'].lower()) + # existing_tasks.append(child['type']['name']) + + for task_name in tasks: + task_type = tasks[task_name]["type"] + if task_name.lower() in existing_tasks: + print("Task {} already exists".format(task_name)) + continue + tasks_to_create.append((task_name, task_type)) + + for task_name, task_type in tasks_to_create: + self.create_task( + name=task_name, + task_type=task_type, + parent=entity + ) + try: + self.session.commit() + except Exception: + tp, value, tb = sys.exc_info() + self.session.rollback() + self.session._configure_locations() + six.reraise(tp, value, tb) + + # Incoming links. + self.create_links(entity_data, entity) + try: + self.session.commit() + except Exception: + tp, value, tb = sys.exc_info() + self.session.rollback() + self.session._configure_locations() + six.reraise(tp, value, tb) + + # Create notes. + user = self.session.query( + "User where username is \"{}\"".format(self.session.api_user) + ).first() + if user: + for comment in entity_data.get("comments", []): + entity.create_note(comment, user) + else: + self.log.warning( + "Was not able to query current User {}".format( + self.session.api_user + ) + ) + try: + self.session.commit() + except Exception: + tp, value, tb = sys.exc_info() + self.session.rollback() + self.session._configure_locations() + six.reraise(tp, value, tb) + + # Import children. + if 'childs' in entity_data: + self.import_to_ftrack( + entity_data['childs'], entity) + + def create_links(self, entity_data, entity): + # Clear existing links. + for link in entity.get("incoming_links", []): + self.session.delete(link) + try: + self.session.commit() + except Exception: + tp, value, tb = sys.exc_info() + self.session.rollback() + self.session._configure_locations() + six.reraise(tp, value, tb) + + # Create new links. + for input in entity_data.get("inputs", []): + input_id = io.find_one({"_id": input})["data"]["ftrackId"] + assetbuild = self.session.get("AssetBuild", input_id) + self.log.debug( + "Creating link from {0} to {1}".format( + assetbuild["name"], entity["name"] + ) + ) + self.session.create( + "TypedContextLink", {"from": assetbuild, "to": entity} + ) + + def get_all_task_types(self, project): + tasks = {} + proj_template = project['project_schema'] + temp_task_types = proj_template['_task_type_schema']['types'] + + for type in temp_task_types: + if type['name'] not in tasks: + tasks[type['name']] = type + + return tasks + + def create_task(self, name, task_type, parent): + task = self.session.create('Task', { + 'name': name, + 'parent': parent + }) + # TODO not secured!!! - check if task_type exists + self.log.info(task_type) + self.log.info(self.task_types) + task['type'] = self.task_types[task_type] + + try: + self.session.commit() + except Exception: + tp, value, tb = sys.exc_info() + self.session.rollback() + self.session._configure_locations() + six.reraise(tp, value, tb) + + return task + + def create_entity(self, name, type, parent): + entity = self.session.create(type, { + 'name': name, + 'parent': parent + }) + try: + self.session.commit() + except Exception: + tp, value, tb = sys.exc_info() + self.session.rollback() + self.session._configure_locations() + six.reraise(tp, value, tb) + + return entity + + def auto_sync_off(self, project): + project["custom_attributes"][CUST_ATTR_AUTO_SYNC] = False + + self.log.info("Ftrack autosync swithed off") + + try: + self.session.commit() + except Exception: + tp, value, tb = sys.exc_info() + self.session.rollback() + self.session._configure_locations() + six.reraise(tp, value, tb) + + def auto_sync_on(self, project): + + project["custom_attributes"][CUST_ATTR_AUTO_SYNC] = True + + self.log.info("Ftrack autosync swithed on") + + try: + self.session.commit() + except Exception: + tp, value, tb = sys.exc_info() + self.session.rollback() + self.session._configure_locations() + six.reraise(tp, value, tb) From 98d9f5e5c9ae5acb47e84914ff39fa969f4b6d80 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Fri, 27 Nov 2020 21:42:56 +0100 Subject: [PATCH 151/279] bump version --- pype/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/version.py b/pype/version.py index d0979fd030..e199aa5550 100644 --- a/pype/version.py +++ b/pype/version.py @@ -1 +1 @@ -__version__ = "2.14.0" +__version__ = "2.14.1" From 6a4c768f21182ed2e0a0584311dc4ca3cc6b4b98 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 30 Nov 2020 10:06:48 +0100 Subject: [PATCH 152/279] there are not added nuke arguments in prelaunch hooks --- pype/hooks/hiero/pre_launch_args.py | 14 ++------------ pype/hooks/maya/pre_launch_args.py | 3 ++- pype/hooks/nukestudio/pre_launch_args.py | 14 ++------------ pype/hooks/nukex/pre_launch_args.py | 12 +----------- 4 files changed, 7 insertions(+), 36 deletions(-) diff --git a/pype/hooks/hiero/pre_launch_args.py b/pype/hooks/hiero/pre_launch_args.py index cb03f03b88..7139f57bbb 100644 --- a/pype/hooks/hiero/pre_launch_args.py +++ b/pype/hooks/hiero/pre_launch_args.py @@ -7,18 +7,8 @@ class HieroLaunchArguments(PreLaunchHook): hosts = ["hiero"] def execute(self): - """Prepare suprocess launch arguments for NukeX.""" - # Get executable - executable = self.launch_context.launch_args[0] - - if isinstance(executable, str): - executable = [executable] - - # Add `nukex` argument and make sure it's bind to execuable - executable.append("--hiero") - - self.launch_context.launch_args[0] = executable - + """Prepare suprocess launch arguments for Hiero.""" + # Add path to workfile to arguments if self.data.get("start_last_workfile"): last_workfile = self.data.get("last_workfile_path") if os.path.exists(last_workfile): diff --git a/pype/hooks/maya/pre_launch_args.py b/pype/hooks/maya/pre_launch_args.py index 6aed54a3c3..570c8e79b8 100644 --- a/pype/hooks/maya/pre_launch_args.py +++ b/pype/hooks/maya/pre_launch_args.py @@ -8,7 +8,8 @@ class MayaLaunchArguments(PreLaunchHook): hosts = ["maya"] def execute(self): - """Prepare suprocess launch arguments for NukeX.""" + """Prepare suprocess launch arguments for Maya.""" + # Add path to workfile to arguments if self.data.get("start_last_workfile"): last_workfile = self.data.get("last_workfile_path") if os.path.exists(last_workfile): diff --git a/pype/hooks/nukestudio/pre_launch_args.py b/pype/hooks/nukestudio/pre_launch_args.py index d567f36ad0..a5e04bf956 100644 --- a/pype/hooks/nukestudio/pre_launch_args.py +++ b/pype/hooks/nukestudio/pre_launch_args.py @@ -7,18 +7,8 @@ class NukeStudioLaunchArguments(PreLaunchHook): hosts = ["nukestudio"] def execute(self): - """Prepare suprocess launch arguments for NukeX.""" - # Get executable - executable = self.launch_context.launch_args[0] - - if isinstance(executable, str): - executable = [executable] - - # Add `nukex` argument and make sure it's bind to execuable - executable.append("--studio") - - self.launch_context.launch_args[0] = executable - + """Prepare suprocess launch arguments for NukeStudio.""" + # Add path to workfile to arguments if self.data.get("start_last_workfile"): last_workfile = self.data.get("last_workfile_path") if os.path.exists(last_workfile): diff --git a/pype/hooks/nukex/pre_launch_args.py b/pype/hooks/nukex/pre_launch_args.py index eb0b963926..39ccb5a58a 100644 --- a/pype/hooks/nukex/pre_launch_args.py +++ b/pype/hooks/nukex/pre_launch_args.py @@ -8,17 +8,7 @@ class NukeXLaunchArguments(PreLaunchHook): def execute(self): """Prepare suprocess launch arguments for NukeX.""" - # Get executable - executable = self.launch_context.launch_args[0] - - if isinstance(executable, str): - executable = [executable] - - # Add `nukex` argument and make sure it's bind to execuable - executable.append("--nukex") - - self.launch_context.launch_args[0] = executable - + # Add path to workfile to arguments if self.data.get("start_last_workfile"): last_workfile = self.data.get("last_workfile_path") if os.path.exists(last_workfile): From cf00c0c57729aca8328a9216a37fea718eb4fcff Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 30 Nov 2020 10:06:56 +0100 Subject: [PATCH 153/279] added resolve prelaunch hook --- .../celaction/pre_celaction_registers.py | 3 +- pype/hooks/resolve/pre_resolve_setup.py | 58 +++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 pype/hooks/resolve/pre_resolve_setup.py diff --git a/pype/hooks/celaction/pre_celaction_registers.py b/pype/hooks/celaction/pre_celaction_registers.py index b65deda7f5..f592026699 100644 --- a/pype/hooks/celaction/pre_celaction_registers.py +++ b/pype/hooks/celaction/pre_celaction_registers.py @@ -41,8 +41,7 @@ class CelactionPrelaunchHook(PreLaunchHook): # TODO: change to root path and pyblish standalone to premiere way pype_root_path = os.getenv("PYPE_SETUP_PATH") - path = os.path.join(pype_root_path, - "pype.bat") + path = os.path.join(pype_root_path, "pype.bat") winreg.SetValueEx(hKey, "SubmitAppTitle", 0, winreg.REG_SZ, path) diff --git a/pype/hooks/resolve/pre_resolve_setup.py b/pype/hooks/resolve/pre_resolve_setup.py new file mode 100644 index 0000000000..336fabf0c4 --- /dev/null +++ b/pype/hooks/resolve/pre_resolve_setup.py @@ -0,0 +1,58 @@ +import os +import importlib +from pype.lib import PreLaunchHook +from pype.hosts.resolve import utils + + +class ResolvePrelaunch(PreLaunchHook): + """ + This hook will check if current workfile path has Resolve + project inside. IF not, it initialize it and finally it pass + path to the project by environment variable to Premiere launcher + shell script. + """ + hosts = ["resolve"] + + def execute(self): + # making sure pyton 3.6 is installed at provided path + py36_dir = os.path.normpath(self.env.get("PYTHON36_RESOLVE", "")) + assert os.path.isdir(py36_dir), ( + "Python 3.6 is not installed at the provided folder path. Either " + "make sure the `environments\resolve.json` is having correctly " + "set `PYTHON36_RESOLVE` or make sure Python 3.6 is installed " + f"in given path. \nPYTHON36_RESOLVE: `{py36_dir}`" + ) + self.log.info(f"Path to Resolve Python folder: `{py36_dir}`...") + self.env["PYTHON36_RESOLVE"] = py36_dir + + # setting utility scripts dir for scripts syncing + us_dir = os.path.normpath( + self.env.get("RESOLVE_UTILITY_SCRIPTS_DIR", "") + ) + assert os.path.isdir(us_dir), ( + "Resolve utility script dir does not exists. Either make sure " + "the `environments\resolve.json` is having correctly set " + "`RESOLVE_UTILITY_SCRIPTS_DIR` or reinstall DaVinci Resolve. \n" + f"RESOLVE_UTILITY_SCRIPTS_DIR: `{us_dir}`" + ) + self.log.debug(f"-- us_dir: `{us_dir}`") + + # correctly format path for pre python script + pre_py_sc = os.path.normpath(self.env.get("PRE_PYTHON_SCRIPT", "")) + self.env["PRE_PYTHON_SCRIPT"] = pre_py_sc + self.log.debug(f"-- pre_py_sc: `{pre_py_sc}`...") + try: + __import__("pype.hosts.resolve") + __import__("pyblish") + + except ImportError: + self.log.warning( + "pyblish: Could not load Resolve integration.", + exc_info=True + ) + + else: + # Resolve Setup integration + importlib.reload(utils) + self.log.debug(f"-- utils.__file__: `{utils.__file__}`") + utils.setup(self.env) From 819998f068989614839f629ee4dfecf47aa37ce3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 30 Nov 2020 10:34:11 +0100 Subject: [PATCH 154/279] replaced `is_host` key with `host_name` --- .../system_settings/global/applications.json | 34 +++++++++---------- .../template_host_unchangables.json | 22 ++++++++++-- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/pype/settings/defaults/system_settings/global/applications.json b/pype/settings/defaults/system_settings/global/applications.json index c638f1e3d2..7dd0057110 100644 --- a/pype/settings/defaults/system_settings/global/applications.json +++ b/pype/settings/defaults/system_settings/global/applications.json @@ -3,7 +3,7 @@ "enabled": true, "label": "Autodesk Maya", "icon": "{}/app_icons/maya.png", - "is_host": true, + "host_name": "maya", "environment": { "__environment_keys__": { "maya": [ @@ -107,7 +107,7 @@ "enabled": true, "label": "Autodesk MayaBatch", "icon": "{}/app_icons/maya.png", - "is_host": false, + "host_name": "maya", "environment": { "__environment_keys__": { "mayabatch": [ @@ -205,7 +205,7 @@ "enabled": true, "label": "Nuke", "icon": "{}/app_icons/nuke.png", - "is_host": true, + "host_name": "nuke", "environment": { "__environment_keys__": { "nuke": [ @@ -287,7 +287,7 @@ "enabled": true, "label": "Nuke X", "icon": "{}/app_icons/nuke.png", - "is_host": true, + "host_name": "nuke", "environment": { "__environment_keys__": { "nukex": [ @@ -369,7 +369,7 @@ "enabled": true, "label": "Nuke Studio", "icon": "{}/app_icons/nuke.png", - "is_host": true, + "host_name": "hiero", "environment": { "__environment_keys__": { "nukestudio": [ @@ -453,7 +453,7 @@ "enabled": true, "label": "Hiero", "icon": "{}/app_icons/hiero.png", - "is_host": true, + "host_name": "hiero", "environment": { "__environment_keys__": { "hiero": [ @@ -539,7 +539,7 @@ "enabled": true, "label": "BlackMagic Fusion", "icon": "{}/app_icons/fusion.png", - "is_host": true, + "host_name": "fusion", "environment": { "__environment_keys__": { "fusion": [] @@ -584,7 +584,7 @@ "enabled": true, "label": "Blackmagic DaVinci Resolve", "icon": "{}/app_icons/resolve.png", - "is_host": true, + "host_name": "resolve", "environment": { "__environment_keys__": { "resolve": [ @@ -662,7 +662,7 @@ "enabled": true, "label": "SideFX Houdini", "icon": "{}/app_icons/houdini.png", - "is_host": true, + "host_name": "houdini", "environment": { "__environment_keys__": { "houdini": [ @@ -720,7 +720,7 @@ "enabled": true, "label": "Blender", "icon": "{}/app_icons/blender.png", - "is_host": true, + "host_name": "blender", "environment": { "__environment_keys__": { "blender": [ @@ -775,7 +775,7 @@ "enabled": true, "label": "Toon Boom Harmony", "icon": "{}/app_icons/harmony.png", - "is_host": true, + "host_name": "harmony", "environment": { "__environment_keys__": { "harmony": [ @@ -859,7 +859,7 @@ "enabled": true, "label": "TVPaint", "icon": "{}/app_icons/tvpaint.png", - "is_host": true, + "host_name": "tvpaint", "environment": { "__environment_keys__": { "tvpaint": [ @@ -911,7 +911,7 @@ "enabled": true, "label": "Adobe Photoshop", "icon": "{}/app_icons/photoshop.png", - "is_host": true, + "host_name": "photoshop", "environment": { "__environment_keys__": { "photoshop": [ @@ -971,7 +971,7 @@ "enabled": true, "label": "Adobe AfterEffects", "icon": "{}/app_icons/aftereffects.png", - "is_host": true, + "host_name": "aftereffects", "environment": { "__environment_keys__": { "aftereffects": [ @@ -1031,7 +1031,7 @@ "enabled": true, "label": "CelAction 2D", "icon": "app_icons/celaction.png", - "is_host": true, + "host_name": "celaction", "environment": { "__environment_keys__": { "celaction": [ @@ -1071,7 +1071,7 @@ "enabled": true, "label": "Unreal Editor", "icon": "{}/app_icons/ue4.png'", - "is_host": true, + "host_name": "unreal", "environment": { "__environment_keys__": { "unreal": [ @@ -1165,7 +1165,7 @@ "enabled": true, "label": "DJV View", "icon": "{}/app_icons/djvView.png", - "is_host": false, + "host_name": "", "environment": { "__environment_keys__": { "djvview": [] diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/template_host_unchangables.json b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/template_host_unchangables.json index 732fd06c30..5fde8e9c1e 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/template_host_unchangables.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/template_host_unchangables.json @@ -13,8 +13,24 @@ "roles": ["developer"] }, { - "type": "boolean", - "key": "is_host", - "label": "Has host implementation", + "type": "enum", + "key": "host_name", + "label": "Host implementation", + "enum_items": [ + {"": "< without host >"}, + {"aftereffects": "aftereffects"}, + {"blender": "blender"}, + {"celaction": "celaction"}, + {"fusion": "fusion"}, + {"harmony": "harmony"}, + {"hiero": "hiero"}, + {"houdini": "houdini"}, + {"maya": "maya"}, + {"nuke": "nuke"}, + {"photoshop": "photoshop"}, + {"resolve": "resolve"}, + {"tvpaint": "tvpaint"}, + {"unreal": "unreal"} + ], "roles": ["developer"] }] From 3393933e28071959b02f1702d0a53a652d71d9db Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 30 Nov 2020 10:35:54 +0100 Subject: [PATCH 155/279] application manager load app_group and host_name --- pype/lib/applications.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/pype/lib/applications.py b/pype/lib/applications.py index c1c6fc9301..37eb4f9e71 100644 --- a/pype/lib/applications.py +++ b/pype/lib/applications.py @@ -530,12 +530,12 @@ class ApplicationManager: settings = system_settings() hosts_definitions = settings["global"]["applications"] - for host_name, variant_definitions in hosts_definitions.items(): + for app_group, variant_definitions in hosts_definitions.items(): enabled = variant_definitions["enabled"] - label = variant_definitions.get("label") or host_name + label = variant_definitions.get("label") or app_group variants = variant_definitions.get("variants") or {} icon = variant_definitions.get("icon") - is_host = variant_definitions.get("is_host", False) + host_name = variant_definitions.get("host_name") or None for app_name, app_data in variants.items(): if app_name in self.applications: raise AssertionError(( @@ -553,11 +553,10 @@ class ApplicationManager: if not app_data.get("icon"): app_data["icon"] = icon - is_host = app_data.get("is_host", is_host) - app_data["is_host"] = is_host + app_data["is_host"] = host_name is not None self.applications[app_name] = Application( - host_name, app_name, app_data, self + app_group, app_name, host_name, app_data, self ) tools_definitions = settings["global"]["tools"] @@ -635,19 +634,21 @@ class Application: Object by itself does nothing special. Args: - host_name (str): Host name or rather name of host implementation. + app_group (str): App group name. e.g. "maya", "nuke", "photoshop", etc. app_name (str): Specific version (or variant) of host. e.g. "maya2020", "nuke11.3", etc. + host_name (str): Name of host implementation. app_data (dict): Data for the version containing information about executables, label, variant label, icon or if is enabled. Only required key is `executables`. manager (ApplicationManager): Application manager that created object. """ - def __init__(self, host_name, app_name, app_data, manager): - self.host_name = host_name + def __init__(self, app_group, app_name, host_name, app_data, manager): + self.app_group = app_group self.app_name = app_name + self.host_name = host_name self.app_data = app_data self.manager = manager @@ -768,6 +769,10 @@ class LaunchHook: def host_name(self): return getattr(self.application, "host_name", None) + @property + def app_group(self): + return getattr(self.application, "app_group", None) + @property def app_name(self): return getattr(self.application, "app_name", None) @@ -1010,6 +1015,10 @@ class ApplicationLaunchContext: def host_name(self): return self.application.host_name + @property + def app_group(self): + return self.application.app_group + @property def manager(self): return self.application.manager From c8c8424cb7ac4689fea14e140133e172f29907f8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 30 Nov 2020 10:37:52 +0100 Subject: [PATCH 156/279] hooks filtering works for app_groups and app_names --- pype/lib/applications.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pype/lib/applications.py b/pype/lib/applications.py index 37eb4f9e71..ac45112511 100644 --- a/pype/lib/applications.py +++ b/pype/lib/applications.py @@ -710,6 +710,10 @@ class LaunchHook: order = None # List of host implementations, skipped if empty. hosts = [] + # List of application groups + app_groups = [] + # List of specific application names + app_names = [] # List of platform availability, skipped if empty. platforms = [] @@ -751,6 +755,14 @@ class LaunchHook: if launch_context.host_name not in cls.hosts: return False + if cls.app_groups: + if launch_context.app_group not in cls.app_groups: + return False + + if cls.app_names: + if launch_context.app_name not in cls.app_names: + return False + return True @property From f8868d04bca8bd4951f0ee8958a668c11dbeaafd Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 30 Nov 2020 10:39:17 +0100 Subject: [PATCH 157/279] environments are per app group not per host name --- pype/hooks/global/pre_global_host_data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/hooks/global/pre_global_host_data.py b/pype/hooks/global/pre_global_host_data.py index 787460019d..3f403b43f5 100644 --- a/pype/hooks/global/pre_global_host_data.py +++ b/pype/hooks/global/pre_global_host_data.py @@ -86,7 +86,7 @@ class GlobalHostDataHook(PreLaunchHook): def prepare_host_environments(self): """Modify launch environments based on launched app and context.""" # Keys for getting environments - env_keys = [self.host_name, self.app_name] + env_keys = [self.app_group, self.app_name] asset_doc = self.data.get("asset_doc") if asset_doc: From 19e5ab8b1a28120d6b31d43b4310cfa6495bebc2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 30 Nov 2020 10:40:21 +0100 Subject: [PATCH 158/279] changed current filtering from hosts to app groups --- pype/hooks/aftereffects/pre_launch_args.py | 2 +- pype/hooks/celaction/pre_celaction_registers.py | 2 +- pype/hooks/fusion/pre_fusion_setup.py | 2 +- pype/hooks/harmony/pre_launch_args.py | 2 +- pype/hooks/hiero/pre_launch_args.py | 2 +- pype/hooks/maya/pre_launch_args.py | 2 +- pype/hooks/nukestudio/pre_launch_args.py | 2 +- pype/hooks/nukex/pre_launch_args.py | 2 +- pype/hooks/photoshop/pre_launch_args.py | 2 +- pype/hooks/resolve/pre_resolve_setup.py | 2 +- pype/hooks/tvpaint/pre_install_pywin.py | 2 +- pype/hooks/tvpaint/pre_launch_args.py | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/pype/hooks/aftereffects/pre_launch_args.py b/pype/hooks/aftereffects/pre_launch_args.py index 01406d495c..e39247b983 100644 --- a/pype/hooks/aftereffects/pre_launch_args.py +++ b/pype/hooks/aftereffects/pre_launch_args.py @@ -9,7 +9,7 @@ class AfterEffectsPrelaunchHook(PreLaunchHook): Hook add python executable and execute python script of AfterEffects implementation before AfterEffects executable. """ - hosts = ["aftereffects"] + app_groups = ["aftereffects"] def execute(self): # Pop tvpaint executable diff --git a/pype/hooks/celaction/pre_celaction_registers.py b/pype/hooks/celaction/pre_celaction_registers.py index f592026699..3f9d81fb98 100644 --- a/pype/hooks/celaction/pre_celaction_registers.py +++ b/pype/hooks/celaction/pre_celaction_registers.py @@ -13,7 +13,7 @@ class CelactionPrelaunchHook(PreLaunchHook): shell script. """ workfile_ext = "scn" - hosts = ["celaction"] + app_groups = ["celaction"] platforms = ["windows"] def execute(self): diff --git a/pype/hooks/fusion/pre_fusion_setup.py b/pype/hooks/fusion/pre_fusion_setup.py index ac7dda4250..d4402e9a04 100644 --- a/pype/hooks/fusion/pre_fusion_setup.py +++ b/pype/hooks/fusion/pre_fusion_setup.py @@ -9,7 +9,7 @@ class FusionPrelaunch(PreLaunchHook): This hook will check if current workfile path has Fusion project inside. """ - hosts = ["fusion"] + app_groups = ["fusion"] def execute(self): # making sure pyton 3.6 is installed at provided path diff --git a/pype/hooks/harmony/pre_launch_args.py b/pype/hooks/harmony/pre_launch_args.py index 70fac5bb76..70c05eb352 100644 --- a/pype/hooks/harmony/pre_launch_args.py +++ b/pype/hooks/harmony/pre_launch_args.py @@ -9,7 +9,7 @@ class HarmonyPrelaunchHook(PreLaunchHook): Hook add python executable and execute python script of harmony implementation before harmony executable. """ - hosts = ["harmony"] + app_groups = ["harmony"] def execute(self): # Pop tvpaint executable diff --git a/pype/hooks/hiero/pre_launch_args.py b/pype/hooks/hiero/pre_launch_args.py index 7139f57bbb..feca6dc3eb 100644 --- a/pype/hooks/hiero/pre_launch_args.py +++ b/pype/hooks/hiero/pre_launch_args.py @@ -4,7 +4,7 @@ from pype.lib import PreLaunchHook class HieroLaunchArguments(PreLaunchHook): order = 0 - hosts = ["hiero"] + app_groups = ["hiero"] def execute(self): """Prepare suprocess launch arguments for Hiero.""" diff --git a/pype/hooks/maya/pre_launch_args.py b/pype/hooks/maya/pre_launch_args.py index 570c8e79b8..8b37bac15b 100644 --- a/pype/hooks/maya/pre_launch_args.py +++ b/pype/hooks/maya/pre_launch_args.py @@ -5,7 +5,7 @@ from pype.lib import PreLaunchHook class MayaLaunchArguments(PreLaunchHook): """Add path to last workfile to launch arguments.""" order = 0 - hosts = ["maya"] + app_groups = ["maya"] def execute(self): """Prepare suprocess launch arguments for Maya.""" diff --git a/pype/hooks/nukestudio/pre_launch_args.py b/pype/hooks/nukestudio/pre_launch_args.py index a5e04bf956..e572ca32a2 100644 --- a/pype/hooks/nukestudio/pre_launch_args.py +++ b/pype/hooks/nukestudio/pre_launch_args.py @@ -4,7 +4,7 @@ from pype.lib import PreLaunchHook class NukeStudioLaunchArguments(PreLaunchHook): order = 0 - hosts = ["nukestudio"] + app_groups = ["nukestudio"] def execute(self): """Prepare suprocess launch arguments for NukeStudio.""" diff --git a/pype/hooks/nukex/pre_launch_args.py b/pype/hooks/nukex/pre_launch_args.py index 39ccb5a58a..f0e5cf7733 100644 --- a/pype/hooks/nukex/pre_launch_args.py +++ b/pype/hooks/nukex/pre_launch_args.py @@ -4,7 +4,7 @@ from pype.lib import PreLaunchHook class NukeXLaunchArguments(PreLaunchHook): order = 0 - hosts = ["nukex"] + app_groups = ["nukex"] def execute(self): """Prepare suprocess launch arguments for NukeX.""" diff --git a/pype/hooks/photoshop/pre_launch_args.py b/pype/hooks/photoshop/pre_launch_args.py index 2c88f62157..b13e7d1e0f 100644 --- a/pype/hooks/photoshop/pre_launch_args.py +++ b/pype/hooks/photoshop/pre_launch_args.py @@ -9,7 +9,7 @@ class PhotoshopPrelaunchHook(PreLaunchHook): Hook add python executable and execute python script of photoshop implementation before photoshop executable. """ - hosts = ["photoshop"] + app_groups = ["photoshop"] def execute(self): # Pop tvpaint executable diff --git a/pype/hooks/resolve/pre_resolve_setup.py b/pype/hooks/resolve/pre_resolve_setup.py index 336fabf0c4..4f6d33c6eb 100644 --- a/pype/hooks/resolve/pre_resolve_setup.py +++ b/pype/hooks/resolve/pre_resolve_setup.py @@ -11,7 +11,7 @@ class ResolvePrelaunch(PreLaunchHook): path to the project by environment variable to Premiere launcher shell script. """ - hosts = ["resolve"] + app_groups = ["resolve"] def execute(self): # making sure pyton 3.6 is installed at provided path diff --git a/pype/hooks/tvpaint/pre_install_pywin.py b/pype/hooks/tvpaint/pre_install_pywin.py index b51267934b..ca9242c4c8 100644 --- a/pype/hooks/tvpaint/pre_install_pywin.py +++ b/pype/hooks/tvpaint/pre_install_pywin.py @@ -9,7 +9,7 @@ class PreInstallPyWin(PreLaunchHook): """Hook makes sure there is installed python module pywin32 on windows.""" # WARNING This hook will probably be deprecated in Pype 3 - kept for test order = 10 - hosts = ["tvpaint"] + app_groups = ["tvpaint"] platforms = ["windows"] def execute(self): diff --git a/pype/hooks/tvpaint/pre_launch_args.py b/pype/hooks/tvpaint/pre_launch_args.py index 9d80e6fddb..13ec320fa0 100644 --- a/pype/hooks/tvpaint/pre_launch_args.py +++ b/pype/hooks/tvpaint/pre_launch_args.py @@ -16,7 +16,7 @@ class TvpaintPrelaunchHook(PreLaunchHook): Existence of last workfile is checked. If workfile does not exists tries to copy templated workfile from predefined path. """ - hosts = ["tvpaint"] + app_groups = ["tvpaint"] def execute(self): # Pop tvpaint executable From 622208c015ed16a3074a3326ebe15c8a963b62ab Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 30 Nov 2020 12:54:23 +0100 Subject: [PATCH 159/279] implemented `ApplicationExecutable` for handlind executablesx and arguments --- pype/lib/applications.py | 68 ++++++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 13 deletions(-) diff --git a/pype/lib/applications.py b/pype/lib/applications.py index ac45112511..86c640f2ed 100644 --- a/pype/lib/applications.py +++ b/pype/lib/applications.py @@ -58,8 +58,8 @@ class ApplictionExecutableNotFound(Exception): " are not available on this machine." ) details = "Defined paths:" - for executable_path in application.executables: - details += "\n- " + executable_path + for executable in application.executables: + details += "\n- " + executable.executable_path self.msg = msg.format(application.full_label, application.app_name) self.details = details @@ -535,7 +535,7 @@ class ApplicationManager: label = variant_definitions.get("label") or app_group variants = variant_definitions.get("variants") or {} icon = variant_definitions.get("icon") - host_name = variant_definitions.get("host_name") or None + group_host_name = variant_definitions.get("host_name") or None for app_name, app_data in variants.items(): if app_name in self.applications: raise AssertionError(( @@ -553,6 +553,8 @@ class ApplicationManager: if not app_data.get("icon"): app_data["icon"] = icon + host_name = app_data.get("host_name") or group_host_name + app_data["is_host"] = host_name is not None self.applications[app_name] = Application( @@ -628,6 +630,41 @@ class ApplicationTool: return self.enabled +class ApplicationExecutable: + def __init__(self, executable): + default_launch_args = [] + if isinstance(executable, str): + executable_path = executable + + elif isinstance(executable, list): + executable_path = None + for arg in executable: + if arg: + if executable_path is None: + executable_path = arg + else: + default_launch_args.append(arg) + + self.executable_path = executable_path + self.default_launch_args = default_launch_args + + def __iter__(self): + yield self.executable_path + for arg in self.default_launch_args: + yield arg + + def __str__(self): + return self.executable_path + + def as_args(self): + return list(self) + + def exists(self): + if not self.executable_path: + return False + return os.path.exists(self.executable_path) + + class Application: """Hold information about application. @@ -658,12 +695,17 @@ class Application: self.enabled = app_data.get("enabled", True) self.is_host = app_data.get("is_host", False) - executables = app_data["executables"] - if isinstance(executables, dict): - executables = executables.get(platform.system().lower()) or [] + _executables = app_data["executables"] + if not _executables: + _executables = [] + + elif isinstance(_executables, dict): + _executables = _executables.get(platform.system().lower()) or [] + + executables = [] + for executable in _executables: + executables.append(ApplicationExecutable(executable)) - if not isinstance(executables, list): - executables = [executables] self.executables = executables @property @@ -683,9 +725,9 @@ class Application: Returns (str): Path to executable from `executables` or None if any exists. """ - for executable_path in self.executables: - if os.path.exists(executable_path): - return executable_path + for executable in self.executables: + if executable.exists(): + return executable return None def launch(self, *args, **kwargs): @@ -845,7 +887,7 @@ class ApplicationLaunchContext: Args: application (Application): Application definition. - executable (str): Path to executable. + executable (ApplicationExecutable): Object with path to executable. **data (dict): Any additional data. Data may be used during preparation to store objects usable in multiple places. """ @@ -868,7 +910,7 @@ class ApplicationLaunchContext: self.data["settings_env"] = settings_env # subprocess.Popen launch arguments (first argument in constructor) - self.launch_args = [executable] + self.launch_args = executable.as_args() # Handle launch environemtns passed_env = self.data.pop("env", None) From 7ab49cdf935229eaee59787e452c20bee3801bf3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 30 Nov 2020 13:00:42 +0100 Subject: [PATCH 160/279] fix check of executable path as it does not have to be full path --- pype/lib/applications.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pype/lib/applications.py b/pype/lib/applications.py index 86c640f2ed..fbf949c247 100644 --- a/pype/lib/applications.py +++ b/pype/lib/applications.py @@ -1,13 +1,12 @@ import os import sys -import re import getpass -import json import copy import platform import inspect import logging import subprocess +import distutils.spawn from abc import ABCMeta, abstractmethod import six @@ -649,7 +648,7 @@ class ApplicationExecutable: self.default_launch_args = default_launch_args def __iter__(self): - yield self.executable_path + yield distutils.spawn.find_executable(self.executable_path) for arg in self.default_launch_args: yield arg @@ -662,7 +661,7 @@ class ApplicationExecutable: def exists(self): if not self.executable_path: return False - return os.path.exists(self.executable_path) + return bool(distutils.spawn.find_executable(self.executable_path)) class Application: From c16e925cbe43d7ca103981e48a6e319357e042c0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 30 Nov 2020 13:25:07 +0100 Subject: [PATCH 161/279] removed PathInput --- .../settings/settings/widgets/item_types.py | 3 +- .../settings/settings/widgets/widgets.py | 29 ------------------- 2 files changed, 1 insertion(+), 31 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index fd5364ea17..072d0a3ee6 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -4,7 +4,6 @@ from Qt import QtWidgets, QtCore, QtGui from .widgets import ( ExpandingWidget, NumberSpinBox, - PathInput, GridLabelWidget, ComboBox, NiceCheckbox @@ -1094,7 +1093,7 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): layout.addWidget(label_widget, 0) self.label_widget = label_widget - self.input_field = PathInput(self) + self.input_field = QtWidgets.QLineEdit(self) self.setFocusProxy(self.input_field) layout.addWidget(self.input_field, 1) diff --git a/pype/tools/settings/settings/widgets/widgets.py b/pype/tools/settings/settings/widgets/widgets.py index b64b1aa8ac..d25cd5a8e0 100644 --- a/pype/tools/settings/settings/widgets/widgets.py +++ b/pype/tools/settings/settings/widgets/widgets.py @@ -47,35 +47,6 @@ class ComboBox(QtWidgets.QComboBox): return self.itemData(self.currentIndex(), role=QtCore.Qt.UserRole) -class PathInput(QtWidgets.QLineEdit): - def clear_end_path(self): - value = self.text().strip() - if value.endswith("/"): - while value and value[-1] == "/": - value = value[:-1] - self.setText(value) - - def keyPressEvent(self, event): - # Always change backslash `\` for forwardslash `/` - if event.key() == QtCore.Qt.Key_Backslash: - event.accept() - new_event = QtGui.QKeyEvent( - event.type(), - QtCore.Qt.Key_Slash, - event.modifiers(), - "/", - event.isAutoRepeat(), - event.count() - ) - QtWidgets.QApplication.sendEvent(self, new_event) - return - super(PathInput, self).keyPressEvent(event) - - def focusOutEvent(self, event): - super(PathInput, self).focusOutEvent(event) - self.clear_end_path() - - class ClickableWidget(QtWidgets.QWidget): clicked = QtCore.Signal() From a763088d97433f5273c7d5d6d5dd653fcef73f72 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 30 Nov 2020 13:27:00 +0100 Subject: [PATCH 162/279] path input and path widget may be with arguments --- .../settings/settings/widgets/item_types.py | 48 +++++++++++++++---- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 072d0a3ee6..167afdf4ce 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1069,7 +1069,7 @@ class TextWidget(QtWidgets.QWidget, InputObject): class PathInputWidget(QtWidgets.QWidget, InputObject): default_input_value = "" value_changed = QtCore.Signal(object) - valid_value_types = (str, ) + valid_value_types = (str, list) def __init__( self, input_data, parent, @@ -1081,6 +1081,8 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): self.initial_attributes(input_data, parent, as_widget) + self.with_arguments = input_data.get("with_arguments", False) + layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) @@ -1094,21 +1096,36 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): self.label_widget = label_widget self.input_field = QtWidgets.QLineEdit(self) + self.args_input_field = None + if self.with_arguments: + self.input_field.setPlaceholderText("Executable path") + self.args_input_field = QtWidgets.QLineEdit(self) + self.args_input_field.setPlaceholderText("Arguments") + self.setFocusProxy(self.input_field) layout.addWidget(self.input_field, 1) - self.input_field.textChanged.connect(self._on_value_change) + if self.args_input_field: + layout.addWidget(self.args_input_field, 1) + self.args_input_field.textChanged.connect(self._on_value_change) + def set_value(self, value): self.validate_value(value) - self.input_field.setText(value) - def focusOutEvent(self, event): - self.input_field.clear_end_path() - super(PathInput, self).focusOutEvent(event) + if not isinstance(value, list): + self.input_field.setText(value) + elif self.with_arguments: + self.input_field.setText(value[0]) + self.args_input_field.setText(value[1]) + else: + self.input_field.setText(value[0]) def item_value(self): - return self.input_field.text() + path_value = self.input_field.text() + if self.with_arguments: + return [path_value, self.args_input_field.text()] + return path_value class EnumeratorWidget(QtWidgets.QWidget, InputObject): @@ -3154,6 +3171,7 @@ class PathWidget(QtWidgets.QWidget, SettingObject): self.multiplatform = input_data.get("multiplatform", False) self.multipath = input_data.get("multipath", False) + self.with_arguments = input_data.get("with_arguments", False) self.input_field = None @@ -3195,7 +3213,10 @@ class PathWidget(QtWidgets.QWidget, SettingObject): def create_gui(self): if not self.multiplatform and not self.multipath: - input_data = {"key": self.key} + input_data = { + "key": self.key, + "with_arguments": self.with_arguments + } path_input = PathInputWidget( input_data, self, as_widget=True, label_widget=self.label_widget @@ -3209,7 +3230,10 @@ class PathWidget(QtWidgets.QWidget, SettingObject): if not self.multiplatform: item_schema = { "key": self.key, - "object_type": "path-input" + "object_type": { + "type": "path-input", + "with_arguments": self.with_arguments + } } input_widget = ListWidget( item_schema, self, @@ -3234,9 +3258,13 @@ class PathWidget(QtWidgets.QWidget, SettingObject): } if self.multipath: child_item["type"] = "list" - child_item["object_type"] = "path-input" + child_item["object_type"] = { + "type": "path-input", + "with_arguments": self.with_arguments + } else: child_item["type"] = "path-input" + child_item["with_arguments"] = self.with_arguments item_schema["children"].append(child_item) From c089184789dd118414e42c1f577e01965d014675 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 30 Nov 2020 13:30:51 +0100 Subject: [PATCH 163/279] hosts executables have set `with_arguments` to true --- .../system_settings/global/applications.json | 185 ++++++++++++++---- .../host_settings/template_host_variant.json | 3 +- 2 files changed, 150 insertions(+), 38 deletions(-) diff --git a/pype/settings/defaults/system_settings/global/applications.json b/pype/settings/defaults/system_settings/global/applications.json index 7dd0057110..cce4c4f25e 100644 --- a/pype/settings/defaults/system_settings/global/applications.json +++ b/pype/settings/defaults/system_settings/global/applications.json @@ -39,11 +39,17 @@ "icon": "", "executables": { "windows": [ - "C:\\Program Files\\Autodesk\\Maya2020\\bin\\maya.exe" + [ + "C:\\Program Files\\Autodesk\\Maya2020\\bin\\maya.exe", + "" + ] ], "darwin": [], "linux": [ - "/usr/autodesk/maya2020/bin/maya" + [ + "/usr/autodesk/maya2020/bin/maya", + "" + ] ] }, "environment": { @@ -62,11 +68,17 @@ "icon": "", "executables": { "windows": [ - "C:\\Program Files\\Autodesk\\Maya2019\\bin\\maya.exe" + [ + "C:\\Program Files\\Autodesk\\Maya2019\\bin\\maya.exe", + "" + ] ], "darwin": [], "linux": [ - "/usr/autodesk/maya2019/bin/maya" + [ + "/usr/autodesk/maya2019/bin/maya", + "" + ] ] }, "environment": { @@ -85,11 +97,17 @@ "icon": "", "executables": { "windows": [ - "C:\\Program Files\\Autodesk\\Maya2017\\bin\\maya.exe" + [ + "C:\\Program Files\\Autodesk\\Maya2017\\bin\\maya.exe", + "" + ] ], "darwin": [], "linux": [ - "/usr/autodesk/maya2018/bin/maya" + [ + "/usr/autodesk/maya2018/bin/maya", + "" + ] ] }, "environment": { @@ -143,7 +161,10 @@ "icon": "", "executables": { "windows": [ - "C:\\Program Files\\Autodesk\\Maya2020\\bin\\mayabatch.exe" + [ + "C:\\Program Files\\Autodesk\\Maya2020\\bin\\mayabatch.exe", + "" + ] ], "darwin": [], "linux": [] @@ -164,7 +185,10 @@ "icon": "", "executables": { "windows": [ - "C:\\Program Files\\Autodesk\\Maya2019\\bin\\mayabatch.exe" + [ + "C:\\Program Files\\Autodesk\\Maya2019\\bin\\mayabatch.exe", + "" + ] ], "darwin": [], "linux": [] @@ -185,7 +209,10 @@ "icon": "", "executables": { "windows": [ - "C:\\Program Files\\Autodesk\\Maya2018\\bin\\mayabatch.exe" + [ + "C:\\Program Files\\Autodesk\\Maya2018\\bin\\mayabatch.exe", + "" + ] ], "darwin": [], "linux": [] @@ -230,11 +257,17 @@ "icon": "", "executables": { "windows": [ - "C:\\Program Files\\Nuke12.0v1\\Nuke12.0.exe" + [ + "C:\\Program Files\\Nuke12.0v1\\Nuke12.0.exe", + "" + ] ], "darwin": [], "linux": [ - "/usr/local/Nuke12.0v1/Nuke12.0" + [ + "/usr/local/Nuke12.0v1/Nuke12.0", + "" + ] ] }, "environment": { @@ -250,11 +283,17 @@ "icon": "", "executables": { "windows": [ - "C:\\Program Files\\Nuke11.3v1\\Nuke11.3.exe" + [ + "C:\\Program Files\\Nuke11.3v1\\Nuke11.3.exe", + "" + ] ], "darwin": [], "linux": [ - "/usr/local/Nuke11.3v5/Nuke11.3" + [ + "/usr/local/Nuke11.3v5/Nuke11.3", + "" + ] ] }, "environment": { @@ -270,7 +309,10 @@ "icon": "", "executables": { "windows": [ - "C:\\Program Files\\Nuke11.2v2\\Nuke11.2.exe" + [ + "C:\\Program Files\\Nuke11.2v2\\Nuke11.2.exe", + "" + ] ], "darwin": [], "linux": [] @@ -312,11 +354,17 @@ "icon": "", "executables": { "windows": [ - "C:\\Program Files\\Nuke12.0v1\\Nuke12.0.exe" + [ + "C:\\Program Files\\Nuke12.0v1\\Nuke12.0.exe", + "--nukex" + ] ], "darwin": [], "linux": [ - "/usr/local/Nuke12.0v1/Nuke12.0" + [ + "/usr/local/Nuke12.0v1/Nuke12.0", + "--nukex" + ] ] }, "environment": { @@ -332,11 +380,17 @@ "icon": "", "executables": { "windows": [ - "C:\\Program Files\\Nuke11.3v1\\Nuke11.3.exe" + [ + "C:\\Program Files\\Nuke11.3v1\\Nuke11.3.exe", + "--nukex" + ] ], "darwin": [], "linux": [ - "/usr/local/Nuke11.3v5/Nuke11.3" + [ + "/usr/local/Nuke11.3v5/Nuke11.3", + "--nukex" + ] ] }, "environment": { @@ -352,7 +406,10 @@ "icon": "", "executables": { "windows": [ - "C:\\Program Files\\Nuke11.2v2\\Nuke11.2.exe" + [ + "C:\\Program Files\\Nuke11.2v2\\Nuke11.2.exe", + "--nukex" + ] ], "darwin": [], "linux": [] @@ -398,11 +455,17 @@ "icon": "", "executables": { "windows": [ - "C:\\Program Files\\Nuke12.0v1\\Nuke12.0.exe" + [ + "C:\\Program Files\\Nuke12.0v1\\Nuke12.0.exe", + "--studio" + ] ], "darwin": [], "linux": [ - "/usr/local/Nuke12.0v1/Nuke12.0" + [ + "/usr/local/Nuke12.0v1/Nuke12.0", + "--studio" + ] ] }, "environment": { @@ -418,11 +481,17 @@ "icon": "", "executables": { "windows": [ - "C:\\Program Files\\Nuke11.3v1\\Nuke11.3.exe" + [ + "C:\\Program Files\\Nuke11.3v1\\Nuke11.3.exe", + "--studio" + ] ], "darwin": [], "linux": [ - "/usr/local/Nuke11.3v5/Nuke11.3" + [ + "/usr/local/Nuke11.3v5/Nuke11.3", + "--studio" + ] ] }, "environment": { @@ -482,11 +551,17 @@ "icon": "", "executables": { "windows": [ - "C:\\Program Files\\Nuke12.0v1\\Nuke12.0.exe" + [ + "C:\\Program Files\\Nuke12.0v1\\Nuke12.0.exe", + "--hiero" + ] ], "darwin": [], "linux": [ - "/usr/local/Nuke12.0v1/Nuke12.0" + [ + "/usr/local/Nuke12.0v1/Nuke12.0", + "--hiero" + ] ] }, "environment": { @@ -502,11 +577,17 @@ "icon": "", "executables": { "windows": [ - "C:\\Program Files\\Nuke11.3v1\\Nuke11.3.exe" + [ + "C:\\Program Files\\Nuke11.3v1\\Nuke11.3.exe", + "--hiero" + ] ], "darwin": [], "linux": [ - "/usr/local/Nuke11.3v5/Nuke11.3" + [ + "/usr/local/Nuke11.3v5/Nuke11.3", + "--hiero" + ] ] }, "environment": { @@ -522,7 +603,10 @@ "icon": "", "executables": { "windows": [ - "C:\\Program Files\\Nuke11.2v2\\Nuke11.2.exe" + [ + "C:\\Program Files\\Nuke11.2v2\\Nuke11.2.exe", + "--hiero" + ] ], "darwin": [], "linux": [] @@ -843,7 +927,10 @@ "executables": { "windows": [], "darwin": [ - "/Applications/Toon Boom Harmony 17 Premium/Harmony Premium.app/Contents/MacOS/Harmony Premium" + [ + "/Applications/Toon Boom Harmony 17 Premium/Harmony Premium.app/Contents/MacOS/Harmony Premium", + "" + ] ], "linux": [] }, @@ -876,7 +963,10 @@ "icon": "", "executables": { "windows": [ - "C:\\Program Files\\TVPaint Developpement\\TVPaint Animation 11 (64bits)\\TVPaint Animation 11 (64bits).exe" + [ + "C:\\Program Files\\TVPaint Developpement\\TVPaint Animation 11 (64bits)\\TVPaint Animation 11 (64bits).exe", + "" + ] ], "darwin": [], "linux": [] @@ -894,7 +984,10 @@ "icon": "", "executables": { "windows": [ - "C:\\Program Files (x86)\\TVPaint Developpement\\TVPaint Animation 11 (32bits)\\TVPaint Animation 11 (32bits).exe" + [ + "C:\\Program Files (x86)\\TVPaint Developpement\\TVPaint Animation 11 (32bits)\\TVPaint Animation 11 (32bits).exe", + "" + ] ], "darwin": [], "linux": [] @@ -936,7 +1029,10 @@ "icon": "", "executables": { "windows": [ - "C:\\Program Files\\Adobe\\Adobe Photoshop 2020\\Photoshop.exe" + [ + "C:\\Program Files\\Adobe\\Adobe Photoshop 2020\\Photoshop.exe", + "" + ] ], "darwin": [], "linux": [] @@ -954,7 +1050,10 @@ "icon": "", "executables": { "windows": [ - "C:\\Program Files\\Adobe\\Adobe Photoshop 2021\\Photoshop.exe" + [ + "C:\\Program Files\\Adobe\\Adobe Photoshop 2021\\Photoshop.exe", + "" + ] ], "darwin": [], "linux": [] @@ -996,7 +1095,10 @@ "icon": "", "executables": { "windows": [ - "C:\\Program Files\\Adobe\\Adobe After Effects 2020\\Support Files\\AfterFX.exe" + [ + "C:\\Program Files\\Adobe\\Adobe After Effects 2020\\Support Files\\AfterFX.exe", + "" + ] ], "darwin": [], "linux": [] @@ -1014,7 +1116,10 @@ "icon": "", "executables": { "windows": [ - "C:\\Program Files\\Adobe\\Adobe After Effects 2021\\Support Files\\AfterFX.exe" + [ + "C:\\Program Files\\Adobe\\Adobe After Effects 2021\\Support Files\\AfterFX.exe", + "" + ] ], "darwin": [], "linux": [] @@ -1046,7 +1151,10 @@ "label": "", "variant_label": "Local", "icon": "{}/app_icons/celaction_local.png", - "executables": "", + "executables": [ + "", + "" + ], "environment": { "__environment_keys__": { "celation_Local": [] @@ -1058,7 +1166,10 @@ "label": "", "variant_label": "Pulblish", "icon": "", - "executables": "", + "executables": [ + "", + "" + ], "environment": { "__environment_keys__": { "celation_Publish": [] diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/template_host_variant.json b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/template_host_variant.json index ce3a75e871..cea7da3a81 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/template_host_variant.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/template_host_variant.json @@ -43,7 +43,8 @@ "key": "executables", "label": "Executables", "multiplatform": "{multiplatform}", - "multipath": "{multipath_executables}" + "multipath": "{multipath_executables}", + "with_arguments": true }, { "key": "environment", From 4b3374ac8b14e55503f47fdd5580ba1ff665846c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 30 Nov 2020 13:38:51 +0100 Subject: [PATCH 164/279] avoid accidental combobox value changes on wheel event --- pype/tools/settings/settings/widgets/widgets.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pype/tools/settings/settings/widgets/widgets.py b/pype/tools/settings/settings/widgets/widgets.py index d25cd5a8e0..dc2ccabe10 100644 --- a/pype/tools/settings/settings/widgets/widgets.py +++ b/pype/tools/settings/settings/widgets/widgets.py @@ -32,6 +32,11 @@ class ComboBox(QtWidgets.QComboBox): super(ComboBox, self).__init__(*args, **kwargs) self.currentIndexChanged.connect(self._on_change) + self.setFocusPolicy(QtCore.Qt.StrongFocus) + + def wheelEvent(self, event): + if self.hasFocus(): + return super(ComboBox, self).wheelEvent(event) def _on_change(self, *args, **kwargs): self.value_changed.emit() From e99fc55bd4c233adbb6bedc71f0a124a55bb516c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 30 Nov 2020 17:39:56 +0100 Subject: [PATCH 165/279] renamed labeled_items to collapsable_key --- .../settings/settings/widgets/item_types.py | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index d4942e04d2..25bbe4a515 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1975,7 +1975,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self.origin_key = NOT_SET self.origin_key_label = NOT_SET - if self.labeled_items: + if self.collapsable_key: layout = QtWidgets.QVBoxLayout(self) else: layout = QtWidgets.QHBoxLayout(self) @@ -1996,7 +1996,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): key_label_input = None wrapper_widget = None - if self.labeled_items: + if self.collapsable_key: key_label_input = QtWidgets.QLineEdit(self) wrapper_widget = ExpandingWidget("", self) @@ -2024,7 +2024,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): key_label_input.focusOutEvent = key_label_input_focused_out spacer_widget = None - if not self.labeled_items: + if not self.collapsable_key: spacer_widget = QtWidgets.QWidget(self) spacer_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) spacer_widget.setVisible(False) @@ -2035,7 +2035,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): add_btn.setFixedSize(self._btn_size, self._btn_size) edit_btn = None - if self.labeled_items: + if self.collapsable_key: edit_btn = IconButton( "fa.edit", QtCore.Qt.lightGray, QtCore.Qt.white ) @@ -2050,7 +2050,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): key_input_label_widget = None key_label_input_label_widget = None - if self.labeled_items: + if self.collapsable_key: key_input_label_widget = QtWidgets.QLabel("Key:") key_label_input_label_widget = QtWidgets.QLabel("Label:") wrapper_widget.add_widget_before_label(add_btn) @@ -2116,8 +2116,8 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): return state @property - def labeled_items(self): - return self._parent.labeled_items + def collapsable_key(self): + return self._parent.collapsable_key def key_value(self): return self.key_input.text() @@ -2138,7 +2138,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): return self._is_key_duplicated = duplicated - if self.labeled_items: + if self.collapsable_key: if duplicated: self.set_edit_mode(True) else: @@ -2156,7 +2156,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self._on_enter_press() def _on_enter_press(self): - if not self.labeled_items: + if not self.collapsable_key: return if self._is_empty: @@ -2226,7 +2226,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self.wrapper_widget.label_widget.setText(label) def on_add_clicked(self): - if not self.labeled_items: + if not self.collapsable_key: if self._is_empty: self.set_as_empty(False) else: @@ -2268,7 +2268,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self.value_input.setVisible(not is_empty) self.add_btn.setVisible(is_empty) - if not self.labeled_items: + if not self.collapsable_key: self.key_input.setVisible(not is_empty) self.remove_btn.setEnabled(not is_empty) self.spacer_widget.setVisible(is_empty) @@ -2362,7 +2362,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): return self._parent.input_fields.index(self) def key_label_value(self): - if self.labeled_items: + if self.collapsable_key: return self.key_label_input.text() return NOT_SET @@ -2406,7 +2406,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): schema_data.get("value_is_env_group") or False ) self.hightlight_content = schema_data.get("highlight_content") or False - self.labeled_items = schema_data.get("labeled_items") or False + self.collapsable_key = schema_data.get("collapsable_key") or False object_type = schema_data["object_type"] if isinstance(object_type, dict): @@ -2505,7 +2505,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): label = dynamic_key_labels.get(item_key) self.add_row(key=item_key, label=label, value=item_value) - if self.labeled_items: + if self.collapsable_key: self.add_row(is_empty=True) for input_field in previous_inputs: @@ -2597,7 +2597,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): return output def item_value_with_metadata(self): - if not self.labeled_items: + if not self.collapsable_key: output = self.item_value() else: @@ -2653,7 +2653,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.input_fields.insert(row, item_widget) previous_input = None - if self.labeled_items: + if self.collapsable_key: for input_field in self.input_fields: if previous_input is not None: self.setTabOrder( From 103e17f7b309b8012ad8bcb285e5418d32ed795d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 30 Nov 2020 17:51:18 +0100 Subject: [PATCH 166/279] fix settings loading --- pype/lib/applications.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/lib/applications.py b/pype/lib/applications.py index fbf949c247..ddff9ddcd2 100644 --- a/pype/lib/applications.py +++ b/pype/lib/applications.py @@ -528,7 +528,7 @@ class ApplicationManager: """Refresh applications from settings.""" settings = system_settings() - hosts_definitions = settings["global"]["applications"] + hosts_definitions = settings["applications"] for app_group, variant_definitions in hosts_definitions.items(): enabled = variant_definitions["enabled"] label = variant_definitions.get("label") or app_group @@ -560,7 +560,7 @@ class ApplicationManager: app_group, app_name, host_name, app_data, self ) - tools_definitions = settings["global"]["tools"] + tools_definitions = settings["tools"] for tool_group_name, tool_group_data in tools_definitions.items(): enabled = tool_group_data.get("enabled", True) tool_variants = tool_group_data.get("variants") or {} From 0073903eceef8dd6617c5c24172e8db5cbfd3d0a Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Tue, 1 Dec 2020 16:38:53 +0100 Subject: [PATCH 167/279] change executable and arguments visual ratio --- pype/tools/settings/settings/widgets/item_types.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 1fe8003716..8a1788188d 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1103,11 +1103,11 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): self.args_input_field.setPlaceholderText("Arguments") self.setFocusProxy(self.input_field) - layout.addWidget(self.input_field, 1) + layout.addWidget(self.input_field, 8) self.input_field.textChanged.connect(self._on_value_change) if self.args_input_field: - layout.addWidget(self.args_input_field, 1) + layout.addWidget(self.args_input_field, 2) self.args_input_field.textChanged.connect(self._on_value_change) def set_value(self, value): From 529bca3f9c08779573066ca0dff2790b7cfc16b7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Dec 2020 17:09:41 +0100 Subject: [PATCH 168/279] fixed defaults save in projects --- pype/tools/settings/settings/widgets/base.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index d3128d7546..2e5c2f356b 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -239,14 +239,6 @@ class SystemWidget(QtWidgets.QWidget): if not self.items_are_valid(): return - output = {} - for item in self.input_fields: - output.update(item.config_value()) - - for key in reversed(self.keys): - _output = {key: output} - output = _output - all_values = {} for item in self.input_fields: all_values.update(item.config_value()) @@ -626,6 +618,8 @@ class ProjectWidget(QtWidgets.QWidget): for item in self.input_fields: all_values.update(item.config_value()) + all_values = lib.convert_gui_data_with_metadata(all_values) + for key in reversed(self.keys): _all_values = {key: all_values} all_values = _all_values From d2a110c1a98579af79f31334a5ddb4eb7881b2b5 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Tue, 1 Dec 2020 18:06:24 +0100 Subject: [PATCH 169/279] update standalon publisher with collapsible keys --- .../defaults/project_anatomy/imageio.json | 239 +++++++++--------- .../project_settings/standalonepublisher.json | 14 +- .../schema_project_standalonepublisher.json | 1 + 3 files changed, 137 insertions(+), 117 deletions(-) diff --git a/pype/settings/defaults/project_anatomy/imageio.json b/pype/settings/defaults/project_anatomy/imageio.json index 98ded33370..4e98463ee4 100644 --- a/pype/settings/defaults/project_anatomy/imageio.json +++ b/pype/settings/defaults/project_anatomy/imageio.json @@ -1,122 +1,129 @@ { - "hiero": { - "workfile": { - "ocioConfigName": "nuke-default", - "ocioconfigpath": { - "windows": [], - "darwin": [], - "linux": [] - }, - "workingSpace": "linear", - "sixteenBitLut": "sRGB", - "eightBitLut": "sRGB", - "floatLut": "linear", - "logLut": "Cineon", - "viewerLut": "sRGB", - "thumbnailLut": "sRGB" - }, - "regexInputs": { - "inputs": [{ - "regex": "[^-a-zA-Z0-9](plateRef).*(?=mp4)", - "colorspace": "sRGB" - }] - } - }, - "nuke": { - "workfile": { - "colorManagement": "Nuke", - "OCIO_config": "nuke-default", - "customOCIOConfigPath": { - "windows": [], - "darwin": [], - "linux": [] - }, - "workingSpaceLUT": "linear", - "monitorLut": "sRGB", - "int8Lut": "sRGB", - "int16Lut": "sRGB", - "logLut": "Cineon", - "floatLut": "linear" - }, - "nodes": { - "requiredNodes": [{ - "plugins": [ - "CreateWriteRender" - ], - "nukeNodeClass": "Write", - "knobs": [{ - "name": "file_type", - "value": "exr" + "hiero": { + "workfile": { + "ocioConfigName": "nuke-default", + "ocioconfigpath": { + "windows": [], + "darwin": [], + "linux": [] }, - { - "name": "datatype", - "value": "16 bit half" - }, - { - "name": "compression", - "value": "Zip (1 scanline)" - }, - { - "name": "autocrop", - "value": "True" - }, - { - "name": "tile_color", - "value": "0xff0000ff" - }, - { - "name": "channels", - "value": "rgb" - }, - { - "name": "colorspace", - "value": "linear" - } - ] + "workingSpace": "linear", + "sixteenBitLut": "sRGB", + "eightBitLut": "sRGB", + "floatLut": "linear", + "logLut": "Cineon", + "viewerLut": "sRGB", + "thumbnailLut": "sRGB" }, - { - "plugins": [ - "CreateWritePrerender" - ], - "nukeNodeClass": "Write", - "knobs": [{ - "name": "file_type", - "value": "exr" - }, - { - "name": "datatype", - "value": "16 bit half" - }, - { - "name": "compression", - "value": "Zip (1 scanline)" - }, - { - "name": "autocrop", - "value": "False" - }, - { - "name": "tile_color", - "value": "0xff0000ff" - }, - { - "name": "channels", - "value": "rgb" - }, - { - "name": "colorspace", - "value": "linear" - } - ] + "regexInputs": { + "inputs": [ + { + "regex": "[^-a-zA-Z0-9](plateRef).*(?=mp4)", + "colorspace": "sRGB" + } + ] } - ], - "customNodes": [] }, - "regexInputs": { - "inputs": [{ - "regex": "[^-a-zA-Z0-9]beauty[^-a-zA-Z0-9]", - "colorspace": "linear" - }] + "nuke": { + "workfile": { + "colorManagement": "Nuke", + "OCIO_config": "nuke-default", + "customOCIOConfigPath": { + "windows": [], + "darwin": [], + "linux": [] + }, + "workingSpaceLUT": "linear", + "monitorLut": "sRGB", + "int8Lut": "sRGB", + "int16Lut": "sRGB", + "logLut": "Cineon", + "floatLut": "linear" + }, + "nodes": { + "requiredNodes": [ + { + "plugins": [ + "CreateWriteRender" + ], + "nukeNodeClass": "Write", + "knobs": [ + { + "name": "file_type", + "value": "exr" + }, + { + "name": "datatype", + "value": "16 bit half" + }, + { + "name": "compression", + "value": "Zip (1 scanline)" + }, + { + "name": "autocrop", + "value": "True" + }, + { + "name": "tile_color", + "value": "0xff0000ff" + }, + { + "name": "channels", + "value": "rgb" + }, + { + "name": "colorspace", + "value": "linear" + } + ] + }, + { + "plugins": [ + "CreateWritePrerender" + ], + "nukeNodeClass": "Write", + "knobs": [ + { + "name": "file_type", + "value": "exr" + }, + { + "name": "datatype", + "value": "16 bit half" + }, + { + "name": "compression", + "value": "Zip (1 scanline)" + }, + { + "name": "autocrop", + "value": "False" + }, + { + "name": "tile_color", + "value": "0xff0000ff" + }, + { + "name": "channels", + "value": "rgb" + }, + { + "name": "colorspace", + "value": "linear" + } + ] + } + ], + "customNodes": [] + }, + "regexInputs": { + "inputs": [ + { + "regex": "[^-a-zA-Z0-9]beauty[^-a-zA-Z0-9]", + "colorspace": "linear" + } + ] + } } - } -} +} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/standalonepublisher.json b/pype/settings/defaults/project_settings/standalonepublisher.json index 2b5db54a4f..877055ceef 100644 --- a/pype/settings/defaults/project_settings/standalonepublisher.json +++ b/pype/settings/defaults/project_settings/standalonepublisher.json @@ -10,6 +10,18 @@ } }, "create": { + "__dynamic_keys_labels__": { + "create_workfile": "Workfile", + "create_model": "Model", + "create_rig": "Rig", + "create_pointcache": "Pointcache", + "create_plate": "Plate", + "create_camera": "Camera", + "create_editorial": "Editorial", + "create_image": "Image", + "create_matchmove": "matchmove", + "": "" + }, "create_workfile": { "name": "workfile", "label": "Workfile", @@ -21,7 +33,7 @@ "help": "Working scene backup" }, "create_model": { - "name": "mode", + "name": "model", "label": "Model", "family": "model", "icon": "cube", diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_standalonepublisher.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_standalonepublisher.json index 4a6e5f76ec..1241620dea 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_standalonepublisher.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_standalonepublisher.json @@ -45,6 +45,7 @@ "collapsable": true, "key": "create", "label": "Creator plugins", + "collapsable_key": true, "is_file": true, "object_type": { From 2afe4484a63d6299ab38a595e758be1d45a92249 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Dec 2020 18:15:18 +0100 Subject: [PATCH 170/279] fixed conflict changes --- pype/tools/settings/settings/widgets/item_types.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 7f78d672dd..1f5615a240 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1094,6 +1094,8 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): self.initial_attributes(schema_data, parent, as_widget) + self.with_arguments = schema_data.get("with_arguments", False) + def create_ui(self, label_widget=None): layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -3205,6 +3207,7 @@ class PathWidget(QtWidgets.QWidget, SettingObject): self.multiplatform = schema_data.get("multiplatform", False) self.multipath = schema_data.get("multipath", False) + self.with_arguments = schema_data.get("with_arguments", False) self.input_field = None @@ -3244,8 +3247,11 @@ class PathWidget(QtWidgets.QWidget, SettingObject): def create_ui_inputs(self): if not self.multiplatform and not self.multipath: - input_data = {"key": self.key} - path_input = PathInputWidget(input_data, self, as_widget=True) + item_schema = { + "key": self.key, + "with_arguments": self.with_arguments + } + path_input = PathInputWidget(item_schema, self, as_widget=True) path_input.create_ui(label_widget=self.label_widget) self.setFocusProxy(path_input) From f82e72fad370e827bc6eb89e275c12c0e3ad3d63 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Dec 2020 18:40:25 +0100 Subject: [PATCH 171/279] implemented base of wrapper items --- .../settings/settings/widgets/item_types.py | 210 ++++++++++++++++++ 1 file changed, 210 insertions(+) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 25bbe4a515..a0d98fd1c5 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -3505,6 +3505,216 @@ class PathWidget(QtWidgets.QWidget, SettingObject): return value, self.is_group +class WrapperItemWidget(QtWidgets.QWidget, SettingObject): + value_changed = QtCore.Signal(object) + allow_actions = False + expand_in_grid = True + is_wrapper_item = True + + def __init__( + self, schema_data, parent, as_widget=False, parent_widget=None + ): + if parent_widget is None: + parent_widget = parent + super(WrapperItemWidget, self).__init__(parent_widget) + + self.input_fields = [] + + self.initial_attributes(schema_data, parent, as_widget) + + if self.as_widget: + raise TypeError( + "Wrapper items ({}) can't be used as widgets.".format( + self.__class__.__name__ + ) + ) + + if self.is_group: + raise TypeError( + "Wrapper items ({}) can't be used as groups.".format( + self.__class__.__name__ + ) + ) + + self.setAttribute(QtCore.Qt.WA_TranslucentBackground) + + self.wrapper_initial_attributes(schema_data) + + def wrapper_initial_attributes(self, schema_data): + """Initialization of attributes for specific wrapper.""" + return + + def create_ui(self, label_widget=None): + """UI implementation.""" + raise NotImplementedError( + "Method `create_ui` not implemented." + ) + + def update_style(self): + """Update items styles.""" + return + + def apply_overrides(self, parent_values): + for item in self.input_fields: + item.apply_overrides(parent_values) + + def discard_changes(self): + self._is_modified = False + self._is_overriden = self._was_overriden + self._has_studio_override = self._had_studio_override + + for input_field in self.input_fields: + input_field.discard_changes() + + self._is_modified = self.child_modified + if not self.is_overidable and self.as_widget: + if self.has_studio_override: + self._is_modified = self.studio_value != self.item_value() + else: + self._is_modified = self.default_value != self.item_value() + + self._state = None + self._is_overriden = self._was_overriden + + def remove_overrides(self): + self._is_overriden = False + self._is_modified = False + for input_field in self.input_fields: + input_field.remove_overrides() + + def reset_to_pype_default(self): + for input_field in self.input_fields: + input_field.reset_to_pype_default() + self._has_studio_override = False + + def set_studio_default(self): + for input_field in self.input_fields: + input_field.set_studio_default() + + if self.is_group: + self._has_studio_override = True + + def set_as_overriden(self): + if self.is_overriden: + return + + if self.is_group: + self._is_overriden = True + return + + for item in self.input_fields: + item.set_as_overriden() + + def update_default_values(self, value): + for item in self.input_fields: + item.update_default_values(value) + + def update_studio_values(self, value): + for item in self.input_fields: + item.update_studio_values(value) + + def _on_value_change(self, item=None): + if self.ignore_value_changes: + return + + self.value_changed.emit(self) + if self.any_parent_is_group: + self.hierarchical_style_update() + + @property + def child_has_studio_override(self): + for input_field in self.input_fields: + if ( + input_field.has_studio_override + or input_field.child_has_studio_override + ): + return True + return False + + @property + def child_modified(self): + for input_field in self.input_fields: + if input_field.child_modified: + return True + return False + + @property + def child_overriden(self): + for input_field in self.input_fields: + if input_field.is_overriden or input_field.child_overriden: + return True + return False + + @property + def child_invalid(self): + for input_field in self.input_fields: + if input_field.child_invalid: + return True + return False + + def get_invalid(self): + output = [] + for input_field in self.input_fields: + output.extend(input_field.get_invalid()) + return output + + def hierarchical_style_update(self): + for input_field in self.input_fields: + input_field.hierarchical_style_update() + self.update_style() + + def item_value(self): + output = {} + for input_field in self.input_fields: + # TODO maybe merge instead of update should be used + # NOTE merge is custom function which merges 2 dicts + output.update(input_field.config_value()) + return output + + def config_value(self): + return self.item_value() + + def studio_overrides(self): + if ( + not (self.as_widget or self.any_parent_as_widget) + and not self.has_studio_override + and not self.child_has_studio_override + ): + return NOT_SET, False + + values = {} + groups = [] + for input_field in self.input_fields: + value, is_group = input_field.studio_overrides() + if value is not NOT_SET: + values.update(value) + if is_group: + groups.extend(value.keys()) + if groups: + if METADATA_KEY not in values: + values[METADATA_KEY] = {} + values[METADATA_KEY]["groups"] = groups + return values, self.is_group + + def overrides(self): + if not self.is_overriden and not self.child_overriden: + return NOT_SET, False + + values = {} + groups = [] + for input_field in self.input_fields: + value, is_group = input_field.overrides() + if value is not NOT_SET: + values.update(value) + if is_group: + groups.extend(value.keys()) + if groups: + if METADATA_KEY not in values: + values[METADATA_KEY] = {} + values[METADATA_KEY]["groups"] = groups + return values, self.is_group + + # Proxy for form layout class FormLabel(QtWidgets.QLabel): def __init__(self, *args, **kwargs): From a417d39631424b90a76dc8841a45396e475fe9ac Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Dec 2020 18:41:39 +0100 Subject: [PATCH 172/279] fixed label click --- .../settings/settings/widgets/item_types.py | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index a0d98fd1c5..1a04ac1a8a 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -3717,9 +3717,14 @@ class WrapperItemWidget(QtWidgets.QWidget, SettingObject): # Proxy for form layout class FormLabel(QtWidgets.QLabel): - def __init__(self, *args, **kwargs): + def __init__(self, input_field, *args, **kwargs): super(FormLabel, self).__init__(*args, **kwargs) - self.item = None + self.input_field = input_field + + def mouseReleaseEvent(self, event): + if self.input_field: + return self.input_field.show_actions_menu(event) + return super(FormLabel, self).mouseReleaseEvent(event) class DictFormWidget(QtWidgets.QWidget, SettingObject): @@ -3767,9 +3772,10 @@ class DictFormWidget(QtWidgets.QWidget, SettingObject): klass = TypeToKlass.types.get(item_type) - label_widget = FormLabel(label, self) - item = klass(child_configuration, self) + + label_widget = FormLabel(item, label, self) + item.create_ui(label_widget=label_widget) label_widget.item = item @@ -3781,16 +3787,6 @@ class DictFormWidget(QtWidgets.QWidget, SettingObject): self.input_fields.append(item) return item - def mouseReleaseEvent(self, event): - if event.button() == QtCore.Qt.RightButton: - position = self.mapFromGlobal(QtGui.QCursor().pos()) - widget = self.childAt(position) - if widget and isinstance(widget, FormLabel): - widget.item.mouseReleaseEvent(event) - event.accept() - return - super(DictFormWidget, self).mouseReleaseEvent(event) - def apply_overrides(self, parent_values): for item in self.input_fields: item.apply_overrides(parent_values) From 5059064228c99aad375ecec00ce03439ac67f4a5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Dec 2020 18:47:09 +0100 Subject: [PATCH 173/279] DictFormWidget inherit from and renamed to FormItemWidget --- .../settings/settings/widgets/item_types.py | 188 +----------------- 1 file changed, 4 insertions(+), 184 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 1a04ac1a8a..629ae415ac 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -3727,35 +3727,14 @@ class FormLabel(QtWidgets.QLabel): return super(FormLabel, self).mouseReleaseEvent(event) -class DictFormWidget(QtWidgets.QWidget, SettingObject): - value_changed = QtCore.Signal(object) - allow_actions = False - expand_in_grid = True - is_wrapper_item = True - - def __init__( - self, schema_data, parent, as_widget=False, parent_widget=None - ): - if parent_widget is None: - parent_widget = parent - super(DictFormWidget, self).__init__(parent_widget) - - self.initial_attributes(schema_data, parent, as_widget) - - self._as_widget = False - self._is_group = False - - self.input_fields = [] - +class FormItemWidget(WrapperItemWidget): def create_ui(self, label_widget=None): self.content_layout = QtWidgets.QFormLayout(self) self.content_layout.setContentsMargins(0, 0, 0, 0) - for child_data in self.schema_data.get("children", []): + for child_data in self.schema_data["children"]: self.add_children_gui(child_data) - self.setAttribute(QtCore.Qt.WA_TranslucentBackground) - any_visible = False for input_field in self.input_fields: if not input_field.hidden_by_role: @@ -3763,6 +3742,7 @@ class DictFormWidget(QtWidgets.QWidget, SettingObject): break if not any_visible: + self.hidden_by_role = True self.hide() def add_children_gui(self, child_configuration): @@ -3777,7 +3757,6 @@ class DictFormWidget(QtWidgets.QWidget, SettingObject): label_widget = FormLabel(item, label, self) item.create_ui(label_widget=label_widget) - label_widget.item = item if item.hidden_by_role: label_widget.hide() @@ -3787,165 +3766,6 @@ class DictFormWidget(QtWidgets.QWidget, SettingObject): self.input_fields.append(item) return item - def apply_overrides(self, parent_values): - for item in self.input_fields: - item.apply_overrides(parent_values) - - def discard_changes(self): - self._is_modified = False - self._is_overriden = self._was_overriden - self._has_studio_override = self._had_studio_override - - for input_field in self.input_fields: - input_field.discard_changes() - - self._is_modified = self.child_modified - if not self.is_overidable and self.as_widget: - if self.has_studio_override: - self._is_modified = self.studio_value != self.item_value() - else: - self._is_modified = self.default_value != self.item_value() - - self._state = None - self._is_overriden = self._was_overriden - - def remove_overrides(self): - self._is_overriden = False - self._is_modified = False - for input_field in self.input_fields: - input_field.remove_overrides() - - def reset_to_pype_default(self): - for input_field in self.input_fields: - input_field.reset_to_pype_default() - self._has_studio_override = False - - def set_studio_default(self): - for input_field in self.input_fields: - input_field.set_studio_default() - - if self.is_group: - self._has_studio_override = True - - def set_as_overriden(self): - if self.is_overriden: - return - - if self.is_group: - self._is_overriden = True - return - - for item in self.input_fields: - item.set_as_overriden() - - def update_default_values(self, value): - for item in self.input_fields: - item.update_default_values(value) - - def update_studio_values(self, value): - for item in self.input_fields: - item.update_studio_values(value) - - def _on_value_change(self, item=None): - if self.ignore_value_changes: - return - - self.value_changed.emit(self) - if self.any_parent_is_group: - self.hierarchical_style_update() - - @property - def child_has_studio_override(self): - for input_field in self.input_fields: - if ( - input_field.has_studio_override - or input_field.child_has_studio_override - ): - return True - return False - - @property - def child_modified(self): - for input_field in self.input_fields: - if input_field.child_modified: - return True - return False - - @property - def child_overriden(self): - for input_field in self.input_fields: - if input_field.is_overriden or input_field.child_overriden: - return True - return False - - @property - def child_invalid(self): - for input_field in self.input_fields: - if input_field.child_invalid: - return True - return False - - def get_invalid(self): - output = [] - for input_field in self.input_fields: - output.extend(input_field.get_invalid()) - return output - - def hierarchical_style_update(self): - for input_field in self.input_fields: - input_field.hierarchical_style_update() - - def item_value(self): - output = {} - for input_field in self.input_fields: - # TODO maybe merge instead of update should be used - # NOTE merge is custom function which merges 2 dicts - output.update(input_field.config_value()) - return output - - def config_value(self): - return self.item_value() - - def studio_overrides(self): - if ( - not (self.as_widget or self.any_parent_as_widget) - and not self.has_studio_override - and not self.child_has_studio_override - ): - return NOT_SET, False - - values = {} - groups = [] - for input_field in self.input_fields: - value, is_group = input_field.studio_overrides() - if value is not NOT_SET: - values.update(value) - if is_group: - groups.extend(value.keys()) - if groups: - if METADATA_KEY not in values: - values[METADATA_KEY] = {} - values[METADATA_KEY]["groups"] = groups - return values, self.is_group - - def overrides(self): - if not self.is_overriden and not self.child_overriden: - return NOT_SET, False - - values = {} - groups = [] - for input_field in self.input_fields: - value, is_group = input_field.overrides() - if value is not NOT_SET: - values.update(value) - if is_group: - groups.extend(value.keys()) - if groups: - if METADATA_KEY not in values: - values[METADATA_KEY] = {} - values[METADATA_KEY]["groups"] = groups - return values, self.is_group - class LabelWidget(QtWidgets.QWidget): is_input_type = False @@ -4016,7 +3836,7 @@ TypeToKlass.types["dict-invisible"] = DictWidget # --------------------------------------------- TypeToKlass.types["dict"] = DictWidget TypeToKlass.types["path-widget"] = PathWidget -TypeToKlass.types["form"] = DictFormWidget +TypeToKlass.types["form"] = FormItemWidget TypeToKlass.types["label"] = LabelWidget TypeToKlass.types["separator"] = SplitterWidget From 943e3e997a3c6503083c31e3308937de6259c4b6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Dec 2020 18:48:15 +0100 Subject: [PATCH 174/279] initial commit of collapsable wrapper --- .../settings/settings/widgets/item_types.py | 91 ++++++++++++++++++- 1 file changed, 90 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 629ae415ac..6eb995eb6c 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -3767,6 +3767,91 @@ class FormItemWidget(WrapperItemWidget): return item +class CollapsableWrapperItem(WrapperItemWidget): + def wrapper_initial_attributes(self, schema_data): + self.collapsable = schema_data.get("collapsable", True) + self.collapsed = schema_data.get("collapsed", True) + + def create_ui(self, label_widget=None): + content_widget = QtWidgets.QWidget(self) + content_widget.setObjectName("ContentWidget") + content_widget.setProperty("content_state", "") + + content_layout = QtWidgets.QGridLayout(content_widget) + content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) + + body_widget = ExpandingWidget(self.schema_data["label"], self) + body_widget.set_content_widget(content_widget) + + label_widget = body_widget.label_widget + + main_layout = QtWidgets.QHBoxLayout(self) + main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.setSpacing(0) + if not body_widget: + main_layout.addWidget(content_widget) + else: + main_layout.addWidget(body_widget) + + self.label_widget = label_widget + self.body_widget = body_widget + self.content_layout = content_layout + + if self.collapsable: + if not self.collapsed: + body_widget.toggle_content() + else: + body_widget.hide_toolbox(hide_content=False) + + for child_data in self.schema_data.get("children", []): + self.add_children_gui(child_data) + + any_visible = False + for input_field in self.input_fields: + if not input_field.hidden_by_role: + any_visible = True + break + + if not any_visible: + self.hide() + + def add_children_gui(self, child_configuration): + item_type = child_configuration["type"] + klass = TypeToKlass.types.get(item_type) + + row = self.content_layout.rowCount() + if not getattr(klass, "is_input_type", False): + item = klass(child_configuration, self) + self.content_layout.addWidget(item, row, 0, 1, 2) + return item + + label_widget = None + item = klass(child_configuration, self) + if not item.expand_in_grid: + label = child_configuration.get("label") + if label is not None: + label_widget = GridLabelWidget(label, self) + self.content_layout.addWidget(label_widget, row, 0, 1, 1) + + item.create_ui(label_widget=label_widget) + item.value_changed.connect(self._on_value_change) + + if label_widget: + if item.hidden_by_role: + label_widget.hide() + label_widget.input_field = item + self.content_layout.addWidget(item, row, 1, 1, 1) + else: + self.content_layout.addWidget(item, row, 0, 1, 2) + + self.input_fields.append(item) + return item + + def update_style(self): + """Update items styles.""" + return + + class LabelWidget(QtWidgets.QWidget): is_input_type = False @@ -3836,7 +3921,11 @@ TypeToKlass.types["dict-invisible"] = DictWidget # --------------------------------------------- TypeToKlass.types["dict"] = DictWidget TypeToKlass.types["path-widget"] = PathWidget -TypeToKlass.types["form"] = FormItemWidget +# Wrappers +TypeToKlass.types["form"] = FormItemWidget +TypeToKlass.types["collapsable-wrap"] = CollapsableWrapperItem + +# UI items TypeToKlass.types["label"] = LabelWidget TypeToKlass.types["separator"] = SplitterWidget From 04d3a0e9cb57f17ecd9e408cada845972820e9a1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Dec 2020 19:03:44 +0100 Subject: [PATCH 175/279] item update styles --- .../settings/settings/widgets/item_types.py | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 6eb995eb6c..8ee2e6acb9 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -3620,6 +3620,7 @@ class WrapperItemWidget(QtWidgets.QWidget, SettingObject): self.value_changed.emit(self) if self.any_parent_is_group: self.hierarchical_style_update() + self.update_style() @property def child_has_studio_override(self): @@ -3847,9 +3848,39 @@ class CollapsableWrapperItem(WrapperItemWidget): self.input_fields.append(item) return item - def update_style(self): - """Update items styles.""" - return + def update_style(self, is_overriden=None): + child_has_studio_override = self.child_has_studio_override + child_modified = self.child_modified + child_invalid = self.child_invalid + child_state = self.style_state( + child_has_studio_override, + child_invalid, + self.child_overriden, + child_modified + ) + if child_state: + child_state = "child-{}".format(child_state) + + if child_state != self._child_state: + self.body_widget.side_line_widget.setProperty("state", child_state) + self.body_widget.side_line_widget.style().polish( + self.body_widget.side_line_widget + ) + self._child_state = child_state + + state = self.style_state( + self.had_studio_override, + child_invalid, + self.is_overriden, + self.is_modified + ) + if self._state == state: + return + + self.label_widget.setProperty("state", state) + self.label_widget.style().polish(self.label_widget) + + self._state = state class LabelWidget(QtWidgets.QWidget): From 6b73060a384c7ab4f7c39afd240788c8638a22d1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Dec 2020 19:13:32 +0100 Subject: [PATCH 176/279] collapsible wrapper added to README and examples --- pype/tools/settings/settings/README.md | 25 ++++++++++++++++--- .../system_schema/example_schema.json | 10 ++++++++ .../settings/settings/widgets/item_types.py | 4 +-- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/pype/tools/settings/settings/README.md b/pype/tools/settings/settings/README.md index 046f903f90..4b75dc38a5 100644 --- a/pype/tools/settings/settings/README.md +++ b/pype/tools/settings/settings/README.md @@ -436,11 +436,9 @@ ## Proxy wrappers - should wraps multiple inputs only visually - these does not have `"key"` key and do not allow to have `"is_file"` or `"is_group"` modifiers enabled +- can't be used as widget (first item in e.g. `list`, `dict-modifiable`, etc.) ### form -- DEPRECATED - - may be used only in `dict` and `dict-invisible` where is currently used grid layout so form is not needed - - item is kept as still may be used in specific cases - wraps inputs into form look layout - should be used only for Pure inputs @@ -462,3 +460,24 @@ ] } ``` + + +### collapsible-wrap +- wraps inputs into collapsible widget + - looks like `dict` but does not hold `"key"` +- should be used only for Pure inputs + +``` +{ + "type": "collapsible-wrap", + "label": "Collapsible example" + "children": [ + { + "type": "text", + "key": "_example_input_collapsible", + "label": "Example input in collapsible wrapper" + }, { + ... + } + ] +} diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/example_schema.json b/pype/tools/settings/settings/gui_schemas/system_schema/example_schema.json index 00595fd3e4..9cbb214d86 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/example_schema.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/example_schema.json @@ -418,6 +418,16 @@ ] } ] + }, { + "type": "collapsible-wrap", + "label": "Collapsible Wrapper without key", + "children": [ + { + "type": "text", + "key": "_example_input_collapsible", + "label": "Example input in collapsible wrapper" + } + ] } ] } diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 8ee2e6acb9..013241d0cd 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -3768,7 +3768,7 @@ class FormItemWidget(WrapperItemWidget): return item -class CollapsableWrapperItem(WrapperItemWidget): +class CollapsibleWrapperItem(WrapperItemWidget): def wrapper_initial_attributes(self, schema_data): self.collapsable = schema_data.get("collapsable", True) self.collapsed = schema_data.get("collapsed", True) @@ -3955,7 +3955,7 @@ TypeToKlass.types["path-widget"] = PathWidget # Wrappers TypeToKlass.types["form"] = FormItemWidget -TypeToKlass.types["collapsable-wrap"] = CollapsableWrapperItem +TypeToKlass.types["collapsible-wrap"] = CollapsibleWrapperItem # UI items TypeToKlass.types["label"] = LabelWidget From cabf5584958874d350a91411d2437d16df9c4466 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Tue, 1 Dec 2020 23:08:41 +0100 Subject: [PATCH 177/279] tweaks to harmony and blender launchers --- .../defaults/system_settings/applications.json | 14 ++++++++++++-- .../host_settings/schema_harmony.json | 8 -------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/pype/settings/defaults/system_settings/applications.json b/pype/settings/defaults/system_settings/applications.json index cce4c4f25e..e5cd249ffe 100644 --- a/pype/settings/defaults/system_settings/applications.json +++ b/pype/settings/defaults/system_settings/applications.json @@ -827,7 +827,12 @@ "variant_label": "2.90", "icon": "", "executables": { - "windows": [], + "windows": [ + [ + "C:\\Program Files\\Blender Foundation\\Blender 2.90\\blender.exe", + "" + ] + ], "darwin": [], "linux": [] }, @@ -843,7 +848,12 @@ "variant_label": "2.83", "icon": "", "executables": { - "windows": [], + "windows": [ + [ + "C:\\Program Files\\Blender Foundation\\Blender 2.83\\blender.exe", + "" + ] + ], "darwin": [], "linux": [] }, diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_harmony.json b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_harmony.json index d7b9e61bda..8ca793f90b 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_harmony.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/schema_harmony.json @@ -30,14 +30,6 @@ "host_version": "20", "host_name": "harmony" }, - { - "host_version": "19", - "host_name": "harmony" - }, - { - "host_version": "18", - "host_name": "harmony" - }, { "host_version": "17", "host_name": "harmony" From e8947ebb7fe504fb90175acf8c9fa615250ee113 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Tue, 1 Dec 2020 23:58:25 +0100 Subject: [PATCH 178/279] fix last workfile quotes in hooks --- pype/hooks/hiero/pre_launch_args.py | 2 +- pype/hooks/maya/pre_launch_args.py | 2 +- pype/hooks/nukestudio/pre_launch_args.py | 2 +- pype/hooks/nukex/pre_launch_args.py | 2 +- pype/hooks/tvpaint/pre_launch_args.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pype/hooks/hiero/pre_launch_args.py b/pype/hooks/hiero/pre_launch_args.py index feca6dc3eb..754f822759 100644 --- a/pype/hooks/hiero/pre_launch_args.py +++ b/pype/hooks/hiero/pre_launch_args.py @@ -13,5 +13,5 @@ class HieroLaunchArguments(PreLaunchHook): last_workfile = self.data.get("last_workfile_path") if os.path.exists(last_workfile): self.launch_context.launch_args.append( - "\"{}\"".format(last_workfile) + "{}.format(last_workfile) ) diff --git a/pype/hooks/maya/pre_launch_args.py b/pype/hooks/maya/pre_launch_args.py index 8b37bac15b..c2b0d75751 100644 --- a/pype/hooks/maya/pre_launch_args.py +++ b/pype/hooks/maya/pre_launch_args.py @@ -14,5 +14,5 @@ class MayaLaunchArguments(PreLaunchHook): last_workfile = self.data.get("last_workfile_path") if os.path.exists(last_workfile): self.launch_context.launch_args.append( - "\"{}\"".format(last_workfile) + "{}".format(last_workfile) ) diff --git a/pype/hooks/nukestudio/pre_launch_args.py b/pype/hooks/nukestudio/pre_launch_args.py index e572ca32a2..5a8cd7b297 100644 --- a/pype/hooks/nukestudio/pre_launch_args.py +++ b/pype/hooks/nukestudio/pre_launch_args.py @@ -13,5 +13,5 @@ class NukeStudioLaunchArguments(PreLaunchHook): last_workfile = self.data.get("last_workfile_path") if os.path.exists(last_workfile): self.launch_context.launch_args.append( - "\"{}\"".format(last_workfile) + "{}".format(last_workfile) ) diff --git a/pype/hooks/nukex/pre_launch_args.py b/pype/hooks/nukex/pre_launch_args.py index f0e5cf7733..911346ec12 100644 --- a/pype/hooks/nukex/pre_launch_args.py +++ b/pype/hooks/nukex/pre_launch_args.py @@ -13,5 +13,5 @@ class NukeXLaunchArguments(PreLaunchHook): last_workfile = self.data.get("last_workfile_path") if os.path.exists(last_workfile): self.launch_context.launch_args.append( - "\"{}\"".format(last_workfile) + "{}".format(last_workfile) ) diff --git a/pype/hooks/tvpaint/pre_launch_args.py b/pype/hooks/tvpaint/pre_launch_args.py index 13ec320fa0..e277656af8 100644 --- a/pype/hooks/tvpaint/pre_launch_args.py +++ b/pype/hooks/tvpaint/pre_launch_args.py @@ -37,7 +37,7 @@ class TvpaintPrelaunchHook(PreLaunchHook): workfile_path = self.workfile_path() if workfile_path: new_launch_args.append( - "\"{}\"".format(workfile_path) + "{}".format(workfile_path) ) # How to create new command line From eff81178816f0aa423c7911b54a13447568e7d80 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Tue, 1 Dec 2020 23:58:44 +0100 Subject: [PATCH 179/279] simplify application labels --- .../system_settings/applications.json | 52 ++++--------------- 1 file changed, 10 insertions(+), 42 deletions(-) diff --git a/pype/settings/defaults/system_settings/applications.json b/pype/settings/defaults/system_settings/applications.json index e5cd249ffe..b0e9635ca8 100644 --- a/pype/settings/defaults/system_settings/applications.json +++ b/pype/settings/defaults/system_settings/applications.json @@ -1,7 +1,7 @@ { "maya": { "enabled": true, - "label": "Autodesk Maya", + "label": "Maya", "icon": "{}/app_icons/maya.png", "host_name": "maya", "environment": { @@ -123,7 +123,7 @@ }, "mayabatch": { "enabled": true, - "label": "Autodesk MayaBatch", + "label": "MayaBatch", "icon": "{}/app_icons/maya.png", "host_name": "maya", "environment": { @@ -621,7 +621,7 @@ }, "fusion": { "enabled": true, - "label": "BlackMagic Fusion", + "label": "Fusion", "icon": "{}/app_icons/fusion.png", "host_name": "fusion", "environment": { @@ -666,7 +666,7 @@ }, "resolve": { "enabled": true, - "label": "Blackmagic DaVinci Resolve", + "label": "Resolve", "icon": "{}/app_icons/resolve.png", "host_name": "resolve", "environment": { @@ -744,7 +744,7 @@ }, "houdini": { "enabled": true, - "label": "SideFX Houdini", + "label": "Houdini", "icon": "{}/app_icons/houdini.png", "host_name": "houdini", "environment": { @@ -867,7 +867,7 @@ }, "harmony": { "enabled": true, - "label": "Toon Boom Harmony", + "label": "Harmony", "icon": "{}/app_icons/harmony.png", "host_name": "harmony", "environment": { @@ -897,38 +897,6 @@ } } }, - "harmony_19": { - "enabled": true, - "label": "", - "variant_label": "19", - "icon": "", - "executables": { - "windows": [], - "darwin": [], - "linux": [] - }, - "environment": { - "__environment_keys__": { - "harmony_19": [] - } - } - }, - "harmony_18": { - "enabled": true, - "label": "", - "variant_label": "18", - "icon": "", - "executables": { - "windows": [], - "darwin": [], - "linux": [] - }, - "environment": { - "__environment_keys__": { - "harmony_18": [] - } - } - }, "harmony_17": { "enabled": true, "label": "", @@ -969,7 +937,7 @@ "tvpaint_Animation 11 (64bits)": { "enabled": true, "label": "", - "variant_label": "Animation 11 (64bits)", + "variant_label": "11 (64bits)", "icon": "", "executables": { "windows": [ @@ -990,7 +958,7 @@ "tvpaint_Animation 11 (32bits)": { "enabled": true, "label": "", - "variant_label": "Animation 11 (32bits)", + "variant_label": "11 (32bits)", "icon": "", "executables": { "windows": [ @@ -1012,7 +980,7 @@ }, "photoshop": { "enabled": true, - "label": "Adobe Photoshop", + "label": "Photoshop", "icon": "{}/app_icons/photoshop.png", "host_name": "photoshop", "environment": { @@ -1078,7 +1046,7 @@ }, "aftereffects": { "enabled": true, - "label": "Adobe AfterEffects", + "label": "AfterEffects", "icon": "{}/app_icons/aftereffects.png", "host_name": "aftereffects", "environment": { From a10bd5d55e67e2c8ce8368f5acf388c14d4b412b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Dec 2020 09:19:45 +0100 Subject: [PATCH 180/279] fixed syntax error and simplified workfile argument --- pype/hooks/celaction/pre_celaction_registers.py | 4 +--- pype/hooks/hiero/pre_launch_args.py | 4 +--- pype/hooks/maya/pre_launch_args.py | 4 +--- pype/hooks/nukestudio/pre_launch_args.py | 4 +--- pype/hooks/nukex/pre_launch_args.py | 4 +--- pype/hooks/tvpaint/pre_launch_args.py | 4 +--- 6 files changed, 6 insertions(+), 18 deletions(-) diff --git a/pype/hooks/celaction/pre_celaction_registers.py b/pype/hooks/celaction/pre_celaction_registers.py index 3f9d81fb98..04ecf82c5c 100644 --- a/pype/hooks/celaction/pre_celaction_registers.py +++ b/pype/hooks/celaction/pre_celaction_registers.py @@ -20,9 +20,7 @@ class CelactionPrelaunchHook(PreLaunchHook): # Add workfile path to launch arguments workfile_path = self.workfile_path() if workfile_path: - self.launch_context.launch_args.append( - "\"{}\"".format(workfile_path) - ) + self.launch_context.launch_args.append(workfile_path) project_name = self.data["project_name"] asset_name = self.data["asset_name"] diff --git a/pype/hooks/hiero/pre_launch_args.py b/pype/hooks/hiero/pre_launch_args.py index 754f822759..6f5d0c0b00 100644 --- a/pype/hooks/hiero/pre_launch_args.py +++ b/pype/hooks/hiero/pre_launch_args.py @@ -12,6 +12,4 @@ class HieroLaunchArguments(PreLaunchHook): if self.data.get("start_last_workfile"): last_workfile = self.data.get("last_workfile_path") if os.path.exists(last_workfile): - self.launch_context.launch_args.append( - "{}.format(last_workfile) - ) + self.launch_context.launch_args.append(last_workfile) diff --git a/pype/hooks/maya/pre_launch_args.py b/pype/hooks/maya/pre_launch_args.py index c2b0d75751..26b935ea01 100644 --- a/pype/hooks/maya/pre_launch_args.py +++ b/pype/hooks/maya/pre_launch_args.py @@ -13,6 +13,4 @@ class MayaLaunchArguments(PreLaunchHook): if self.data.get("start_last_workfile"): last_workfile = self.data.get("last_workfile_path") if os.path.exists(last_workfile): - self.launch_context.launch_args.append( - "{}".format(last_workfile) - ) + self.launch_context.launch_args.append(last_workfile) diff --git a/pype/hooks/nukestudio/pre_launch_args.py b/pype/hooks/nukestudio/pre_launch_args.py index 5a8cd7b297..6056441042 100644 --- a/pype/hooks/nukestudio/pre_launch_args.py +++ b/pype/hooks/nukestudio/pre_launch_args.py @@ -12,6 +12,4 @@ class NukeStudioLaunchArguments(PreLaunchHook): if self.data.get("start_last_workfile"): last_workfile = self.data.get("last_workfile_path") if os.path.exists(last_workfile): - self.launch_context.launch_args.append( - "{}".format(last_workfile) - ) + self.launch_context.launch_args.append(last_workfile) diff --git a/pype/hooks/nukex/pre_launch_args.py b/pype/hooks/nukex/pre_launch_args.py index 911346ec12..979bfcce0b 100644 --- a/pype/hooks/nukex/pre_launch_args.py +++ b/pype/hooks/nukex/pre_launch_args.py @@ -12,6 +12,4 @@ class NukeXLaunchArguments(PreLaunchHook): if self.data.get("start_last_workfile"): last_workfile = self.data.get("last_workfile_path") if os.path.exists(last_workfile): - self.launch_context.launch_args.append( - "{}".format(last_workfile) - ) + self.launch_context.launch_args.append(last_workfile) diff --git a/pype/hooks/tvpaint/pre_launch_args.py b/pype/hooks/tvpaint/pre_launch_args.py index e277656af8..210b1e99c3 100644 --- a/pype/hooks/tvpaint/pre_launch_args.py +++ b/pype/hooks/tvpaint/pre_launch_args.py @@ -36,9 +36,7 @@ class TvpaintPrelaunchHook(PreLaunchHook): # Add workfile to launch arguments workfile_path = self.workfile_path() if workfile_path: - new_launch_args.append( - "{}".format(workfile_path) - ) + new_launch_args.append(workfile_path) # How to create new command line # if platform.system().lower() == "windows": From 5bb86beee906e8b962addc71847c4daab360a15f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Dec 2020 12:01:27 +0100 Subject: [PATCH 181/279] fixed add button in modifiable dictionary --- .../tools/settings/settings/widgets/item_types.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index e8a7397d9f..64b4fe32e6 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2040,15 +2040,16 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): key_label_input.focusOutEvent = key_label_input_focused_out spacer_widget = None + add_btn = None if not self.collapsable_key: spacer_widget = QtWidgets.QWidget(self) spacer_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) spacer_widget.setVisible(False) - add_btn = QtWidgets.QPushButton("+") - add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - add_btn.setProperty("btn-type", "tool-item") - add_btn.setFixedSize(self._btn_size, self._btn_size) + add_btn = QtWidgets.QPushButton("+") + add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + add_btn.setProperty("btn-type", "tool-item") + add_btn.setFixedSize(self._btn_size, self._btn_size) edit_btn = None if self.collapsable_key: @@ -2069,7 +2070,6 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): if self.collapsable_key: key_input_label_widget = QtWidgets.QLabel("Key:") key_label_input_label_widget = QtWidgets.QLabel("Label:") - wrapper_widget.add_widget_before_label(add_btn) wrapper_widget.add_widget_before_label(edit_btn) wrapper_widget.add_widget_after_label(key_input_label_widget) wrapper_widget.add_widget_after_label(key_input) @@ -2093,8 +2093,8 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): key_label_input.returnPressed.connect(self._on_enter_press) value_input.value_changed.connect(self._on_value_change) - - add_btn.clicked.connect(self.on_add_clicked) + if add_btn: + add_btn.clicked.connect(self.on_add_clicked) if edit_btn: edit_btn.clicked.connect(self.on_edit_pressed) remove_btn.clicked.connect(self.on_remove_clicked) @@ -2283,7 +2283,6 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self._is_empty = is_empty self.value_input.setVisible(not is_empty) - self.add_btn.setVisible(is_empty) if not self.collapsable_key: self.key_input.setVisible(not is_empty) self.remove_btn.setEnabled(not is_empty) From 0a253f96e0fd948429e19cf79db9a89ca3f18292 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Dec 2020 12:01:53 +0100 Subject: [PATCH 182/279] modifiable dict cna handle required keys --- .../settings/settings/widgets/item_types.py | 43 ++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 64b4fe32e6..8bbbb0e9c9 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2422,6 +2422,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): ) self.hightlight_content = schema_data.get("highlight_content") or False self.collapsable_key = schema_data.get("collapsable_key") or False + self.required_keys = schema_data.get("required_keys") or [] object_type = schema_data["object_type"] if isinstance(object_type, dict): @@ -2503,7 +2504,14 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.setAttribute(QtCore.Qt.WA_TranslucentBackground) - self.add_row(is_empty=True) + last_required_item = None + for key in self.required_keys: + last_required_item = self.add_row(key=key, is_required=True) + + if last_required_item: + last_required_item.set_as_last_required() + else: + self.add_row(is_empty=True) def count(self): return len(self.input_fields) @@ -2513,10 +2521,17 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): metadata = value.get(METADATA_KEY, {}) dynamic_key_labels = metadata.get("dynamic_key_label") or {} - previous_inputs = tuple(self.input_fields) + + required_items = list(self.required_inputs_by_key.values()) + previous_inputs = list() + for input_field in self.input_fields: + if input_field not in required_items: + previous_inputs.append(input_field) + for item_key, item_value in value.items(): if item_key is METADATA_KEY: continue + label = dynamic_key_labels.get(item_key) self.add_row(key=item_key, label=label, value=item_value) @@ -2648,9 +2663,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): def config_value(self): return {self.key: self.item_value_with_metadata()} - def add_row( - self, row=None, key=None, label=None, value=None, is_empty=False - ): + def _create_item(self, row, key, is_empty, is_required): # Create new item item_widget = ModifiableDictItem( self.item_schema, self, self.content_widget @@ -2658,6 +2671,10 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): if is_empty: item_widget.set_as_empty() + if is_required: + item_widget.set_as_required(key) + self.required_inputs_by_key[key] = item_widget + item_widget.value_changed.connect(self._on_value_change) if row is None: @@ -2686,6 +2703,20 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.setTabOrder( input_field.key_input, previous_input ) + return item_widget + + def add_row( + self, + row=None, + key=None, + label=None, + value=None, + is_empty=False, + is_required=False + ): + item_widget = self.required_inputs_by_key.get(key) + if not item_widget: + item_widget = self._create_item(row, key, is_empty, is_required) # Set value if entered value is not None # else (when add button clicked) trigger `_on_value_change` @@ -2701,6 +2732,8 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self._on_value_change() self.parent().updateGeometry() + return item_widget + def remove_row(self, item_widget): item_widget.value_changed.disconnect() From 751e6afe70abc14a58bec0bd6bd6a8d5e804f1a5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Dec 2020 12:02:15 +0100 Subject: [PATCH 183/279] modified modifiable dict item to handle required keys --- .../settings/settings/widgets/item_types.py | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 8bbbb0e9c9..063262c43f 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1988,6 +1988,8 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self._is_empty = False self._is_key_duplicated = False + self._is_required = False + self.origin_key = NOT_SET self.origin_key_label = NOT_SET @@ -2161,6 +2163,24 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self._on_focus_lose() self.update_style() + def set_as_required(self, key): + self.key_input.setText(key) + self.key_input.setEnabled(False) + self._is_required = True + + if self._is_empty: + self.set_as_empty(False) + + if self.collapsable_key: + self.remove_btn.setVisible(False) + else: + self.remove_btn.setEnabled(False) + self.add_btn.setEnabled(False) + + def set_as_last_required(self): + if self.add_btn: + self.add_btn.setEnabled(True) + def _on_focus_lose(self): if ( self.edit_btn.hasFocus() @@ -2272,9 +2292,13 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self.key_input.setVisible(enabled) self.key_input_label_widget.setVisible(enabled) self.key_label_input.setVisible(enabled) - self.remove_btn.setVisible(enabled) + if not self._is_required: + self.remove_btn.setVisible(enabled) if enabled: - self.key_input.setFocus() + if self.key_input.isEnabled(): + self.key_input.setFocus() + else: + self.key_label_input.setFocus() def on_remove_clicked(self): self._parent.remove_row(self) @@ -2414,6 +2438,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.initial_attributes(schema_data, parent, as_widget) self.input_fields = [] + self.required_inputs_by_key = {} # Validation of "key" key self.key = schema_data["key"] From 0785e1b032913248281245e094f9b407502ba5b0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Dec 2020 12:46:44 +0100 Subject: [PATCH 184/279] updated readme --- pype/tools/settings/settings/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pype/tools/settings/settings/README.md b/pype/tools/settings/settings/README.md index 4b75dc38a5..53f21aad06 100644 --- a/pype/tools/settings/settings/README.md +++ b/pype/tools/settings/settings/README.md @@ -310,6 +310,9 @@ - items in this input can be removed and added same way as in `list` input - value items in dictionary must be the same type - type of items is defined with key `"object_type"` +- required keys may be defined under `"required_keys"` + - required keys must be defined as a list (e.g. `["key_1"]`) and are moved to the top + - these keys can't be removed or edited (it is possible to edit label if item is collapsible) - there are 2 possible ways how to set the type: 1.) dictionary with item modifiers (`number` input has `minimum`, `maximum` and `decimals`) in that case item type must be set as value of `"type"` (example below) 2.) item type name as string without modifiers (e.g. `text`) From bc75ef7563543909957124c4d23a83ee92b7ebd3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Dec 2020 17:03:56 +0100 Subject: [PATCH 185/279] implemented base for settings category SettingsCategoryWidget --- pype/tools/settings/settings/widgets/base.py | 275 +++++++++++++++++++ 1 file changed, 275 insertions(+) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index 2e5c2f356b..11f973a91f 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -33,6 +33,281 @@ from avalon import io from avalon.vendor import qtawesome +class SettingsCategoryWidget(QtWidgets.QWidget): + schema_category = None + initial_schema_name = None + + def __init__(self, user_role, parent=None): + super(SettingsCategoryWidget, self).__init__(parent) + + self.user_role = user_role + + self.initialize_attributes() + self.create_ui() + self.reset() + + def initialize_attributes(self): + self._hide_studio_overrides = False + self._ignore_value_changes = False + + self.keys = [] + self.input_fields = [] + self.schema = None + self.main_schema_key = None + + # Required attributes for items + self.is_overidable = False + self._has_studio_override = False + self._is_overriden = False + self._as_widget = False + self._is_group = False + self._any_parent_as_widget = False + self._any_parent_is_group = False + self.has_studio_override = self._has_studio_override + self.is_overriden = self._is_overriden + self.as_widget = self._as_widget + self.is_group = self._as_widget + self.any_parent_as_widget = self._any_parent_as_widget + self.any_parent_is_group = self._any_parent_is_group + + def create_ui(self): + scroll_widget = QtWidgets.QScrollArea(self) + scroll_widget.setObjectName("GroupWidget") + content_widget = QtWidgets.QWidget(scroll_widget) + content_layout = QtWidgets.QVBoxLayout(content_widget) + content_layout.setContentsMargins(3, 3, 3, 3) + content_layout.setSpacing(0) + content_layout.setAlignment(QtCore.Qt.AlignTop) + + scroll_widget.setWidgetResizable(True) + scroll_widget.setWidget(content_widget) + + footer_widget = QtWidgets.QWidget() + footer_layout = QtWidgets.QHBoxLayout(footer_widget) + + if self.user_role == "developer": + self._add_developer_ui(footer_layout) + + save_btn = QtWidgets.QPushButton("Save") + spacer_widget = QtWidgets.QWidget() + footer_layout.addWidget(spacer_widget, 1) + footer_layout.addWidget(save_btn, 0) + + configurations_widget = QtWidgets.QWidget() + configurations_layout = QtWidgets.QVBoxLayout(configurations_widget) + configurations_layout.setContentsMargins(0, 0, 0, 0) + configurations_layout.setSpacing(0) + + configurations_layout.addWidget(scroll_widget, 1) + configurations_layout.addWidget(footer_widget, 0) + + main_layout = QtWidgets.QHBoxLayout(self) + main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.setSpacing(0) + main_layout.addWidget(configurations_widget, 1) + + save_btn.clicked.connect(self._save) + + self.scroll_widget = scroll_widget + self.content_layout = content_layout + self.content_widget = content_widget + self.configurations_widget = configurations_widget + self.main_layout = main_layout + + self.ui_tweaks() + + def ui_tweaks(self): + return + + def _add_developer_ui(self, footer_layout): + save_as_default_btn = QtWidgets.QPushButton("Save as Default") + + refresh_icon = qtawesome.icon("fa.refresh", color="white") + refresh_button = QtWidgets.QPushButton() + refresh_button.setIcon(refresh_icon) + + hide_studio_overrides = QtWidgets.QCheckBox() + hide_studio_overrides.setChecked(self._hide_studio_overrides) + + hide_studio_overrides_widget = QtWidgets.QWidget() + hide_studio_overrides_layout = QtWidgets.QHBoxLayout( + hide_studio_overrides_widget + ) + _label_widget = QtWidgets.QLabel( + "Hide studio overrides", hide_studio_overrides_widget + ) + hide_studio_overrides_layout.addWidget(_label_widget) + hide_studio_overrides_layout.addWidget(hide_studio_overrides) + + footer_layout.addWidget(save_as_default_btn, 0) + footer_layout.addWidget(refresh_button, 0) + footer_layout.addWidget(hide_studio_overrides_widget, 0) + + save_as_default_btn.clicked.connect(self._save_as_defaults) + refresh_button.clicked.connect(self._on_refresh) + hide_studio_overrides.stateChanged.connect( + self._on_hide_studio_overrides + ) + + def save(self): + """Save procedure.""" + raise NotImplementedError("Method `save` is not implemented.") + + def defaults_dir(self): + """Path to defaults folder.""" + raise NotImplementedError("Method `defaults_dir` is not implemented.") + + def update_values(self): + """Procedure of update values of items on context change or reset.""" + raise NotImplementedError("Method `update_values` is not implemented.") + + def validate_defaults_to_save(self, value): + raise NotImplementedError( + "Method `validate_defaults_to_save` not implemented." + ) + + def any_parent_overriden(self): + return False + + @property + def ignore_value_changes(self): + return self._ignore_value_changes + + @ignore_value_changes.setter + def ignore_value_changes(self, value): + self._ignore_value_changes = value + if value is False: + self.hierarchical_style_update() + + def hierarchical_style_update(self): + for input_field in self.input_fields: + input_field.hierarchical_style_update() + + def reset(self): + reset_default_settings() + + self.keys.clear() + self.input_fields.clear() + while self.content_layout.count() != 0: + widget = self.content_layout.itemAt(0).widget() + self.content_layout.removeWidget(widget) + widget.deleteLater() + + self.schema = lib.gui_schema( + self.schema_category, self.initial_schema_name + ) + + self.main_schema_key = self.schema["key"] + + self.add_children_gui(self.schema) + self._update_values() + self.hierarchical_style_update() + + def items_are_valid(self): + has_invalid = False + for item in self.input_fields: + if item.child_invalid: + has_invalid = True + + if not has_invalid: + return True + + invalid_items = [] + for item in self.input_fields: + invalid_items.extend(item.get_invalid()) + msg_box = QtWidgets.QMessageBox( + QtWidgets.QMessageBox.Warning, + "Invalid input", + "There is invalid value in one of inputs." + " Please lead red color and fix them." + ) + msg_box.setStandardButtons(QtWidgets.QMessageBox.Ok) + msg_box.exec_() + + first_invalid_item = invalid_items[0] + self.scroll_widget.ensureWidgetVisible(first_invalid_item) + if first_invalid_item.isVisible(): + first_invalid_item.setFocus(True) + return False + + def _save(self): + if not self.items_are_valid(): + return + + self.save() + + self._update_values() + + def _on_refresh(self): + self.reset() + + def _on_hide_studio_overrides(self, state): + self._hide_studio_overrides = (state == QtCore.Qt.Checked) + self._update_values() + self.hierarchical_style_update() + + def _save_as_defaults(self): + if not self.items_are_valid(): + return + + all_values = {} + for item in self.input_fields: + all_values.update(item.config_value()) + + for key in reversed(self.keys): + all_values = {key: all_values} + + # Skip first key and convert data to store + all_values = lib.convert_gui_data_with_metadata( + all_values[self.main_schema_key] + ) + + if not self.validate_defaults_to_save(all_values): + return + + defaults_dir = self.defaults_dir() + keys_to_file = lib.file_keys_from_schema(self.schema) + for key_sequence in keys_to_file: + # Skip first key + key_sequence = key_sequence[1:] + subpath = "/".join(key_sequence) + ".json" + + new_values = all_values + for key in key_sequence: + new_values = new_values[key] + + output_path = os.path.join(defaults_dir, subpath) + dirpath = os.path.dirname(output_path) + if not os.path.exists(dirpath): + os.makedirs(dirpath) + + print("Saving data to: ", subpath) + with open(output_path, "w") as file_stream: + json.dump(new_values, file_stream, indent=4) + + reset_default_settings() + + self._update_values() + self.hierarchical_style_update() + + def _update_values(self): + self.ignore_value_changes = True + self.update_values() + self.ignore_value_changes = False + + def add_children_gui(self, child_configuration): + klass = lib.TypeToKlass.types.get(child_configuration["type"]) + item = klass(child_configuration, self) + item.create_ui() + self.input_fields.append(item) + self.content_layout.addWidget(item, 0) + + # Add spacer to stretch children guis + self.content_layout.addWidget( + QtWidgets.QWidget(self.content_widget), 1 + ) + + class SystemWidget(QtWidgets.QWidget): is_overidable = False has_studio_override = _has_studio_override = False From 58349615c73c7bdb2b939fac945884a180006219 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Dec 2020 17:05:29 +0100 Subject: [PATCH 186/279] SystemWidget is using new SettingsCategory as base --- pype/tools/settings/settings/widgets/base.py | 240 ++----------------- 1 file changed, 21 insertions(+), 219 deletions(-) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index 11f973a91f..ba5868737a 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -308,153 +308,17 @@ class SettingsCategoryWidget(QtWidgets.QWidget): ) -class SystemWidget(QtWidgets.QWidget): - is_overidable = False - has_studio_override = _has_studio_override = False - is_overriden = _is_overriden = False - as_widget = _as_widget = False - any_parent_as_widget = _any_parent_as_widget = False - is_group = _is_group = False - any_parent_is_group = _any_parent_is_group = False +class SystemWidget(SettingsCategoryWidget): + schema_category = "system_schema" + initial_schema_name = "schema_main" - def __init__(self, user_role, parent=None): - super(SystemWidget, self).__init__(parent) - - self.user_role = user_role - self._hide_studio_overrides = False - self._ignore_value_changes = False - - self.input_fields = [] + def initialize_attributes(self): self.environ_fields = [] - - scroll_widget = QtWidgets.QScrollArea(self) - scroll_widget.setObjectName("GroupWidget") - content_widget = QtWidgets.QWidget(scroll_widget) - content_layout = QtWidgets.QVBoxLayout(content_widget) - content_layout.setContentsMargins(3, 3, 3, 3) - content_layout.setSpacing(0) - content_layout.setAlignment(QtCore.Qt.AlignTop) - content_widget.setLayout(content_layout) - - scroll_widget.setWidgetResizable(True) - scroll_widget.setWidget(content_widget) - - self.scroll_widget = scroll_widget - self.content_layout = content_layout - self.content_widget = content_widget - - footer_widget = QtWidgets.QWidget() - footer_layout = QtWidgets.QHBoxLayout(footer_widget) - - if self.user_role == "developer": - save_as_default_btn = QtWidgets.QPushButton("Save as Default") - save_as_default_btn.clicked.connect(self._save_as_defaults) - - refresh_icon = qtawesome.icon("fa.refresh", color="white") - refresh_button = QtWidgets.QPushButton() - refresh_button.setIcon(refresh_icon) - refresh_button.clicked.connect(self._on_refresh) - - hide_studio_overrides = QtWidgets.QCheckBox() - hide_studio_overrides.setChecked(self._hide_studio_overrides) - hide_studio_overrides.stateChanged.connect( - self._on_hide_studio_overrides - ) - - hide_studio_overrides_widget = QtWidgets.QWidget() - hide_studio_overrides_layout = QtWidgets.QHBoxLayout( - hide_studio_overrides_widget - ) - _label_widget = QtWidgets.QLabel( - "Hide studio overrides", hide_studio_overrides_widget - ) - hide_studio_overrides_layout.addWidget(_label_widget) - hide_studio_overrides_layout.addWidget(hide_studio_overrides) - - footer_layout.addWidget(save_as_default_btn, 0) - footer_layout.addWidget(refresh_button, 0) - footer_layout.addWidget(hide_studio_overrides_widget, 0) - - save_btn = QtWidgets.QPushButton("Save") - spacer_widget = QtWidgets.QWidget() - footer_layout.addWidget(spacer_widget, 1) - footer_layout.addWidget(save_btn, 0) - - layout = QtWidgets.QVBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(0) - self.setLayout(layout) - - layout.addWidget(scroll_widget, 1) - layout.addWidget(footer_widget, 0) - - save_btn.clicked.connect(self._save) - - self.reset() - - def any_parent_overriden(self): - return False - - @property - def ignore_value_changes(self): - return self._ignore_value_changes - - @ignore_value_changes.setter - def ignore_value_changes(self, value): - self._ignore_value_changes = value - if value is False: - self.hierarchical_style_update() - - def hierarchical_style_update(self): - for input_field in self.input_fields: - input_field.hierarchical_style_update() + super(SystemWidget, self).initialize_attributes() def add_environ_field(self, input_field): self.environ_fields.append(input_field) - def reset(self): - reset_default_settings() - - self.input_fields.clear() - self.environ_fields.clear() - while self.content_layout.count() != 0: - widget = self.content_layout.itemAt(0).widget() - self.content_layout.removeWidget(widget) - widget.deleteLater() - - self.schema = lib.gui_schema("system_schema", "schema_main") - self.keys = self.schema.get("keys", []) - self.add_children_gui(self.schema) - self._update_values() - self.hierarchical_style_update() - - def items_are_valid(self): - has_invalid = False - for item in self.input_fields: - if item.child_invalid: - has_invalid = True - - if not has_invalid: - return True - - invalid_items = [] - for item in self.input_fields: - invalid_items.extend(item.get_invalid()) - msg_box = QtWidgets.QMessageBox( - QtWidgets.QMessageBox.Warning, - "Invalid input", - "There is invalid value in one of inputs." - " Please lead red color and fix them." - ) - msg_box.setStandardButtons(QtWidgets.QMessageBox.Ok) - msg_box.exec_() - - first_invalid_item = invalid_items[0] - self.scroll_widget.ensureWidgetVisible(first_invalid_item) - if first_invalid_item.isVisible(): - first_invalid_item.setFocus(True) - return False - def duplicated_env_group_validation(self, values=None, overrides=None): try: if overrides is not None: @@ -483,83 +347,35 @@ class SystemWidget(QtWidgets.QWidget): return False return True - def _save(self): - if not self.items_are_valid(): - return + def defaults_dir(self): + return os.path.join(DEFAULTS_DIR, SYSTEM_SETTINGS_KEY) + def validate_defaults_to_save(self, values): + return self.duplicated_env_group_validation(values) + + def reset(self): + self.environ_fields.clear() + super(SystemWidget, self).reset() + + def save(self, all_values): _data = {} for input_field in self.input_fields: value, _is_group = input_field.studio_overrides() if value is not lib.NOT_SET: _data.update(value) - values = lib.convert_gui_data_to_overrides(_data.get("system", {})) + values = lib.convert_gui_data_to_overrides( + _data.get(self.main_schema_key, {}) + ) if not self.duplicated_env_group_validation(overrides=values): return save_studio_settings(values) - self._update_values() - - def _on_refresh(self): - self.reset() - - def _on_hide_studio_overrides(self, state): - self._hide_studio_overrides = (state == QtCore.Qt.Checked) - self._update_values() - self.hierarchical_style_update() - - def _save_as_defaults(self): - if not self.items_are_valid(): - return - - all_values = {} - for item in self.input_fields: - all_values.update(item.config_value()) - - for key in reversed(self.keys): - _all_values = {key: all_values} - all_values = _all_values - - # Skip first key - all_values = lib.convert_gui_data_with_metadata(all_values["system"]) - - if not self.duplicated_env_group_validation(all_values): - return - - prject_defaults_dir = os.path.join( - DEFAULTS_DIR, SYSTEM_SETTINGS_KEY - ) - keys_to_file = lib.file_keys_from_schema(self.schema) - for key_sequence in keys_to_file: - # Skip first key - key_sequence = key_sequence[1:] - subpath = "/".join(key_sequence) + ".json" - - new_values = all_values - for key in key_sequence: - new_values = new_values[key] - - output_path = os.path.join(prject_defaults_dir, subpath) - dirpath = os.path.dirname(output_path) - if not os.path.exists(dirpath): - os.makedirs(dirpath) - - print("Saving data to: ", subpath) - with open(output_path, "w") as file_stream: - json.dump(new_values, file_stream, indent=4) - - reset_default_settings() - - self._update_values() - self.hierarchical_style_update() - - def _update_values(self): - self.ignore_value_changes = True - + def update_values(self): default_values = lib.convert_data_to_gui_data({ - "system": default_settings()[SYSTEM_SETTINGS_KEY] + self.main_schema_key: default_settings()[SYSTEM_SETTINGS_KEY] }) for input_field in self.input_fields: input_field.update_default_values(default_values) @@ -568,26 +384,12 @@ class SystemWidget(QtWidgets.QWidget): system_values = lib.NOT_SET else: system_values = lib.convert_overrides_to_gui_data( - {"system": studio_system_settings()} + {self.main_schema_key: studio_system_settings()} ) for input_field in self.input_fields: input_field.update_studio_values(system_values) - self.ignore_value_changes = False - - def add_children_gui(self, child_configuration): - item_type = child_configuration["type"] - klass = lib.TypeToKlass.types.get(item_type) - item = klass(child_configuration, self) - item.create_ui() - self.input_fields.append(item) - self.content_layout.addWidget(item, 0) - - # Add spacer to stretch children guis - spacer = QtWidgets.QWidget(self.content_widget) - self.content_layout.addWidget(spacer, 1) - class ProjectListView(QtWidgets.QListView): left_mouse_released_at = QtCore.Signal(QtCore.QModelIndex) From 9f992d4f890628dec24c05d04ab45e699018be4a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Dec 2020 17:06:01 +0100 Subject: [PATCH 187/279] ProjectWidget is also using setting category as base --- pype/tools/settings/settings/widgets/base.py | 251 ++----------------- 1 file changed, 25 insertions(+), 226 deletions(-) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index ba5868737a..c1ff640837 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -517,145 +517,30 @@ class ProjectListWidget(QtWidgets.QWidget): ) -class ProjectWidget(QtWidgets.QWidget): - has_studio_override = _has_studio_override = False - is_overriden = _is_overriden = False - as_widget = _as_widget = False - any_parent_as_widget = _any_parent_as_widget = False - is_group = _is_group = False - any_parent_is_group = _any_parent_is_group = False +class ProjectWidget(SettingsCategoryWidget): + schema_category = "projects_schema" + initial_schema_name = "schema_main" - def __init__(self, user_role, parent=None): - super(ProjectWidget, self).__init__(parent) - - self.user_role = user_role - self._hide_studio_overrides = False - - self.is_overidable = False - self._ignore_value_changes = False + def initialize_attributes(self): self.project_name = None - self.input_fields = [] - - scroll_widget = QtWidgets.QScrollArea(self) - scroll_widget.setObjectName("GroupWidget") - content_widget = QtWidgets.QWidget(scroll_widget) - content_layout = QtWidgets.QVBoxLayout(content_widget) - content_layout.setContentsMargins(3, 3, 3, 3) - content_layout.setSpacing(0) - content_layout.setAlignment(QtCore.Qt.AlignTop) - content_widget.setLayout(content_layout) - - scroll_widget.setWidgetResizable(True) - scroll_widget.setWidget(content_widget) + super(ProjectWidget, self).initialize_attributes() + def ui_tweaks(self): project_list_widget = ProjectListWidget(self) - content_layout.addWidget(project_list_widget) - footer_widget = QtWidgets.QWidget() - footer_layout = QtWidgets.QHBoxLayout(footer_widget) + self.main_layout.insertWidget(0, project_list_widget, 0) - if self.user_role == "developer": - save_as_default_btn = QtWidgets.QPushButton("Save as Default") - save_as_default_btn.clicked.connect(self._save_as_defaults) - - refresh_icon = qtawesome.icon("fa.refresh", color="white") - refresh_button = QtWidgets.QPushButton() - refresh_button.setIcon(refresh_icon) - refresh_button.clicked.connect(self._on_refresh) - - hide_studio_overrides = QtWidgets.QCheckBox() - hide_studio_overrides.setChecked(self._hide_studio_overrides) - hide_studio_overrides.stateChanged.connect( - self._on_hide_studio_overrides - ) - - hide_studio_overrides_widget = QtWidgets.QWidget() - hide_studio_overrides_layout = QtWidgets.QHBoxLayout( - hide_studio_overrides_widget - ) - _label_widget = QtWidgets.QLabel( - "Hide studio overrides", hide_studio_overrides_widget - ) - hide_studio_overrides_layout.addWidget(_label_widget) - hide_studio_overrides_layout.addWidget(hide_studio_overrides) - - footer_layout.addWidget(save_as_default_btn, 0) - footer_layout.addWidget(refresh_button, 0) - footer_layout.addWidget(hide_studio_overrides_widget, 0) - - save_btn = QtWidgets.QPushButton("Save") - spacer_widget = QtWidgets.QWidget() - footer_layout.addWidget(spacer_widget, 1) - footer_layout.addWidget(save_btn, 0) - - configurations_widget = QtWidgets.QWidget() - configurations_layout = QtWidgets.QVBoxLayout(configurations_widget) - configurations_layout.setContentsMargins(0, 0, 0, 0) - configurations_layout.setSpacing(0) - - configurations_layout.addWidget(scroll_widget, 1) - configurations_layout.addWidget(footer_widget, 0) - - layout = QtWidgets.QHBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(0) - self.setLayout(layout) - - layout.addWidget(project_list_widget, 0) - layout.addWidget(configurations_widget, 1) - - save_btn.clicked.connect(self._save_overrides) project_list_widget.project_changed.connect(self._on_project_change) self.project_list_widget = project_list_widget - self.scroll_widget = scroll_widget - self.content_layout = content_layout - self.content_widget = content_widget - self.reset() + def defaults_dir(self): + return DEFAULTS_DIR - def any_parent_overriden(self): - return False - - @property - def ignore_value_changes(self): - return self._ignore_value_changes - - @ignore_value_changes.setter - def ignore_value_changes(self, value): - self._ignore_value_changes = value - if value is False: - self.hierarchical_style_update() - - def hierarchical_style_update(self): - for input_field in self.input_fields: - input_field.hierarchical_style_update() - - def reset(self): - self.input_fields.clear() - while self.content_layout.count() != 0: - widget = self.content_layout.itemAt(0).widget() - self.content_layout.removeWidget(widget) - widget.deleteLater() - - self.schema = lib.gui_schema("projects_schema", "0_project_gui_schema") - self.keys = self.schema.get("keys", []) - self.add_children_gui(self.schema) - self._update_values() - self.hierarchical_style_update() - - def add_children_gui(self, child_configuration): - item_type = child_configuration["type"] - klass = lib.TypeToKlass.types.get(item_type) - item = klass(child_configuration, self) - item.create_ui() - self.input_fields.append(item) - self.content_layout.addWidget(item, 0) - - # Add spacer to stretch children guis - spacer = QtWidgets.QWidget(self.content_widget) - self.content_layout.addWidget(spacer, 1) + def validate_defaults_to_save(self, _): + # Projects does not have any specific validations + return True def _on_project_change(self): project_name = self.project_list_widget.project_name() @@ -668,7 +553,7 @@ class ProjectWidget(QtWidgets.QWidget): _project_anatomy = project_anatomy_overrides(project_name) self.is_overidable = True - overrides = {"project": { + overrides = {self.main_schema_key: { PROJECT_SETTINGS_KEY: lib.convert_overrides_to_gui_data( _project_overrides ), @@ -682,103 +567,19 @@ class ProjectWidget(QtWidgets.QWidget): item.apply_overrides(overrides) self.ignore_value_changes = False - def _save_as_defaults(self): - output = {} - for item in self.input_fields: - output.update(item.config_value()) - - for key in reversed(self.keys): - _output = {key: output} - output = _output - - all_values = {} - for item in self.input_fields: - all_values.update(item.config_value()) - - all_values = lib.convert_gui_data_with_metadata(all_values) - - for key in reversed(self.keys): - _all_values = {key: all_values} - all_values = _all_values - - # Skip first key - all_values = all_values["project"] - - keys_to_file = lib.file_keys_from_schema(self.schema) - for key_sequence in keys_to_file: - # Skip first key - key_sequence = key_sequence[1:] - subpath = "/".join(key_sequence) + ".json" - - new_values = all_values - for key in key_sequence: - new_values = new_values[key] - - output_path = os.path.join(DEFAULTS_DIR, subpath) - dirpath = os.path.dirname(output_path) - if not os.path.exists(dirpath): - os.makedirs(dirpath) - - print("Saving data to: ", subpath) - with open(output_path, "w") as file_stream: - json.dump(new_values, file_stream, indent=4) - - reset_default_settings() - - self._update_values() - self.hierarchical_style_update() - - def items_are_valid(self): - has_invalid = False - for item in self.input_fields: - if item.child_invalid: - has_invalid = True - - if not has_invalid: - return True - - invalid_items = [] - for item in self.input_fields: - invalid_items.extend(item.get_invalid()) - msg_box = QtWidgets.QMessageBox( - QtWidgets.QMessageBox.Warning, - "Invalid input", - "There is invalid value in one of inputs." - " Please lead red color and fix them." - ) - msg_box.setStandardButtons(QtWidgets.QMessageBox.Ok) - msg_box.exec_() - - first_invalid_item = invalid_items[0] - self.scroll_widget.ensureWidgetVisible(first_invalid_item) - if first_invalid_item.isVisible(): - first_invalid_item.setFocus(True) - return False - - def _on_refresh(self): - self.reset() - - def _on_hide_studio_overrides(self, state): - self._hide_studio_overrides = (state == QtCore.Qt.Checked) - self._update_values() - self.hierarchical_style_update() - - def _save_overrides(self): - if not self.items_are_valid(): - return - + def save(self): data = {} studio_overrides = bool(self.project_name is None) for item in self.input_fields: if studio_overrides: - value, is_group = item.studio_overrides() + value, _is_group = item.studio_overrides() else: - value, is_group = item.overrides() + value, _is_group = item.overrides() if value is not lib.NOT_SET: data.update(value) output_data = lib.convert_gui_data_to_overrides( - data.get("project") or {} + data.get(self.main_schema_key) or {} ) # Saving overrides data @@ -796,11 +597,9 @@ class ProjectWidget(QtWidgets.QWidget): # Update saved values self._update_values() - def _update_values(self): - self.ignore_value_changes = True - + def update_values(self): default_values = lib.convert_data_to_gui_data( - {"project": default_settings()} + {self.main_schema_key: default_settings()} ) for input_field in self.input_fields: input_field.update_default_values(default_values) @@ -808,12 +607,12 @@ class ProjectWidget(QtWidgets.QWidget): if self._hide_studio_overrides: studio_values = lib.NOT_SET else: - studio_values = lib.convert_overrides_to_gui_data({"project": { - PROJECT_SETTINGS_KEY: studio_project_settings(), - PROJECT_ANATOMY_KEY: studio_project_anatomy() - }}) + studio_values = lib.convert_overrides_to_gui_data({ + self.main_schema_key: { + PROJECT_SETTINGS_KEY: studio_project_settings(), + PROJECT_ANATOMY_KEY: studio_project_anatomy() + } + }) for input_field in self.input_fields: input_field.update_studio_values(studio_values) - - self.ignore_value_changes = False From f19a240f689b128895fc63b8afc84afec6ef0c29 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Dec 2020 17:06:23 +0100 Subject: [PATCH 188/279] 0_project_gui_schema renamed to schema_main --- .../{0_project_gui_schema.json => schema_main.json} | 0 .../settings/gui_schemas/system_schema/schema_main.json | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename pype/tools/settings/settings/gui_schemas/projects_schema/{0_project_gui_schema.json => schema_main.json} (100%) diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_main.json similarity index 100% rename from pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json rename to pype/tools/settings/settings/gui_schemas/projects_schema/schema_main.json diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/schema_main.json b/pype/tools/settings/settings/gui_schemas/system_schema/schema_main.json index d5c7402dcf..ae6622098e 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/schema_main.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/schema_main.json @@ -4,7 +4,7 @@ "children": [{ "type": "schema", "name": "schema_general" - },{ + }, { "type": "schema", "name": "schema_modules" }, { From ce0465aab961ab547c6699f82fdce5afdbe56f7f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Dec 2020 18:28:43 +0100 Subject: [PATCH 189/279] anatomy item is loading schemas dynamically --- .../settings/widgets/anatomy_types.py | 25 ++++++------------- 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/pype/tools/settings/settings/widgets/anatomy_types.py b/pype/tools/settings/settings/widgets/anatomy_types.py index 83183e7943..9a20df3ae4 100644 --- a/pype/tools/settings/settings/widgets/anatomy_types.py +++ b/pype/tools/settings/settings/widgets/anatomy_types.py @@ -37,9 +37,7 @@ class AnatomyWidget(QtWidgets.QWidget, SettingObject): "representation": "png" } - def __init__( - self, schema_data, parent, as_widget=False - ): + def __init__(self, schema_data, parent, as_widget=False): if as_widget: raise TypeError( "`AnatomyWidget` does not allow to be used as widget." @@ -49,25 +47,16 @@ class AnatomyWidget(QtWidgets.QWidget, SettingObject): self.initial_attributes(schema_data, parent, as_widget) + self.input_fields = [] + self.key = schema_data["key"] def create_ui(self, label_widget=None): children_data = self.schema_data["children"] - roots_input_data = {} - templates_input_data = {} - imageio_input_data = {} - for child in children_data: - if child["type"] == "anatomy_roots": - roots_input_data = child - elif child["type"] == "anatomy_templates": - templates_input_data = child - elif child["key"] == "imageio": - imageio_input_data = child - - self.root_widget = RootsWidget(roots_input_data, self) - self.templates_widget = TemplatesWidget(templates_input_data, self) - self.imageio_widget = DictWidget(imageio_input_data, self) - self.imageio_widget.create_ui() + for schema_data in children_data: + item = TypeToKlass.types[schema_data["type"]](schema_data, self) + item.create_ui() + self.input_fields.append(item) self.setAttribute(QtCore.Qt.WA_StyledBackground) From c6fe33b08a9359ec5f980a6311d394f4895b8bc8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Dec 2020 18:29:22 +0100 Subject: [PATCH 190/279] added required modifications to be able use dynamically loaded items --- .../settings/widgets/anatomy_types.py | 136 ++++++++---------- 1 file changed, 63 insertions(+), 73 deletions(-) diff --git a/pype/tools/settings/settings/widgets/anatomy_types.py b/pype/tools/settings/settings/widgets/anatomy_types.py index 9a20df3ae4..ad24d54050 100644 --- a/pype/tools/settings/settings/widgets/anatomy_types.py +++ b/pype/tools/settings/settings/widgets/anatomy_types.py @@ -72,19 +72,15 @@ class AnatomyWidget(QtWidgets.QWidget, SettingObject): content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) content_layout.setSpacing(5) - content_layout.addWidget(self.root_widget) - content_layout.addWidget(self.templates_widget) - content_layout.addWidget(self.imageio_widget) + for input_field in self.input_fields: + content_layout.addWidget(input_field) + input_field.value_changed.connect(self._on_value_change) body_widget.set_content_widget(content_widget) self.body_widget = body_widget self.label_widget = body_widget.label_widget - self.root_widget.value_changed.connect(self._on_value_change) - self.templates_widget.value_changed.connect(self._on_value_change) - self.imageio_widget.value_changed.connect(self._on_value_change) - def update_default_values(self, parent_values): self._state = None self._child_state = None @@ -94,9 +90,8 @@ class AnatomyWidget(QtWidgets.QWidget, SettingObject): else: value = NOT_SET - self.root_widget.update_default_values(value) - self.templates_widget.update_default_values(value) - self.imageio_widget.update_default_values(value) + for input_field in self.input_fields: + input_field.update_default_values(value) def update_studio_values(self, parent_values): self._state = None @@ -107,9 +102,8 @@ class AnatomyWidget(QtWidgets.QWidget, SettingObject): else: value = NOT_SET - self.root_widget.update_studio_values(value) - self.templates_widget.update_studio_values(value) - self.imageio_widget.update_studio_values(value) + for input_field in self.input_fields: + input_field.update_studio_values(value) def apply_overrides(self, parent_values): # Make sure this is set to False @@ -120,9 +114,8 @@ class AnatomyWidget(QtWidgets.QWidget, SettingObject): if parent_values is not NOT_SET: value = parent_values.get(self.key, value) - self.root_widget.apply_overrides(value) - self.templates_widget.apply_overrides(value) - self.imageio_widget.apply_overrides(value) + for input_field in self.input_fields: + input_field.apply_overrides(value) def set_value(self, value): raise TypeError("AnatomyWidget does not allow to use `set_value`") @@ -156,67 +149,58 @@ class AnatomyWidget(QtWidgets.QWidget, SettingObject): self._child_state = child_state def hierarchical_style_update(self): - self.root_widget.hierarchical_style_update() - self.templates_widget.hierarchical_style_update() - self.imageio_widget.hierarchical_style_update() + for input_field in self.input_fields: + input_field.hierarchical_style_update() + self.update_style() @property def child_has_studio_override(self): - return ( - self.root_widget.child_has_studio_override - or self.templates_widget.child_has_studio_override - or self.imageio_widget.child_has_studio_override - ) + for input_field in self.input_fields: + if input_field.child_has_studio_override: + return True + return False @property def child_modified(self): - return ( - self.root_widget.child_modified - or self.templates_widget.child_modified - or self.imageio_widget.child_modified - ) + for input_field in self.input_fields: + if input_field.child_modified: + return True + return False @property def child_overriden(self): - return ( - self.root_widget.child_overriden - or self.templates_widget.child_overriden - or self.imageio_widget.child_overriden - ) + for input_field in self.input_fields: + if input_field.child_overriden: + return True + return False @property def child_invalid(self): - return ( - self.root_widget.child_invalid - or self.templates_widget.child_invalid - or self.imageio_widget.child_invalid - ) + for input_field in self.input_fields: + if input_field.child_invalid: + return True + return False def set_as_overriden(self): - self.root_widget.set_as_overriden() - self.templates_widget.set_as_overriden() - self.imageio_widget.set_as_overriden() + for input_field in self.input_fields: + input_field.child_invalid.set_as_overriden() def remove_overrides(self): - self.root_widget.remove_overrides() - self.templates_widget.remove_overrides() - self.imageio_widget.remove_overrides() + for input_field in self.input_fields: + input_field.remove_overrides() def reset_to_pype_default(self): - self.root_widget.reset_to_pype_default() - self.templates_widget.reset_to_pype_default() - self.imageio_widget.reset_to_pype_default() + for input_field in self.input_fields: + input_field.reset_to_pype_default() def set_studio_default(self): - self.root_widget.set_studio_default() - self.templates_widget.set_studio_default() - self.imageio_widget.set_studio_default() + for input_field in self.input_fields: + input_field.set_studio_default() def discard_changes(self): - self.root_widget.discard_changes() - self.templates_widget.discard_changes() - self.imageio_widget.discard_changes() + for input_field in self.input_fields: + input_field.discard_changes() def overrides(self): if self.child_overriden: @@ -225,26 +209,30 @@ class AnatomyWidget(QtWidgets.QWidget, SettingObject): def item_value(self): output = {} - output.update(self.root_widget.config_value()) - output.update(self.templates_widget.config_value()) - output.update(self.imageio_widget.config_value()) + for input_field in self.input_fields: + output.update(input_field.config_value()) return output def studio_overrides(self): - if ( - self.root_widget.child_has_studio_override - or self.templates_widget.child_has_studio_override - or self.imageio_widget.child_has_studio_override - ): - groups = [ - self.root_widget.key, - self.templates_widget.key, - self.imageio_widget.key - ] - value = self.config_value() - value[self.key][METADATA_KEY] = {"groups": groups} - return value, True - return NOT_SET, False + has_overrides = False + for input_field in self.input_fields: + if input_field.child_has_studio_override: + has_overrides = True + break + + if not has_overrides: + return NOT_SET, False + + groups = [] + for input_field in self.input_fields: + groups.append(input_field.key) + + value = self.config_value() + if METADATA_KEY not in value[self.key]: + value[self.key][METADATA_KEY] = {} + value[self.key][METADATA_KEY]["groups"] = groups + + return value, True def config_value(self): return {self.key: self.item_value()} @@ -267,6 +255,7 @@ class RootsWidget(QtWidgets.QWidget, SettingObject): self.studio_is_multiroot = False self.was_multiroot = NOT_SET + def create_ui(self, _label_widget=None): checkbox_widget = QtWidgets.QWidget(self) multiroot_label = QtWidgets.QLabel( "Use multiple roots", checkbox_widget @@ -650,6 +639,7 @@ class TemplatesWidget(QtWidgets.QWidget, SettingObject): self.key = input_data["key"] + def create_ui(self, label_widget=None): body_widget = ExpandingWidget("Templates", self) content_widget = QtWidgets.QWidget(body_widget) body_widget.set_content_widget(content_widget) @@ -775,5 +765,5 @@ class TemplatesWidget(QtWidgets.QWidget, SettingObject): TypeToKlass.types["anatomy"] = AnatomyWidget -TypeToKlass.types["anatomy_roots"] = AnatomyWidget -TypeToKlass.types["anatomy_templates"] = AnatomyWidget +TypeToKlass.types["anatomy_roots"] = RootsWidget +TypeToKlass.types["anatomy_templates"] = TemplatesWidget From a294b577e3516ee74f2e55a84566f8b108c33d16 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Wed, 2 Dec 2020 19:53:54 +0100 Subject: [PATCH 191/279] respect original c-space when not using maketx --- pype/plugins/maya/publish/extract_look.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pype/plugins/maya/publish/extract_look.py b/pype/plugins/maya/publish/extract_look.py index 6bd202093f..4a20409809 100644 --- a/pype/plugins/maya/publish/extract_look.py +++ b/pype/plugins/maya/publish/extract_look.py @@ -172,10 +172,11 @@ class ExtractLook(pype.api.Extractor): cspace = files_metadata[filepath]["color_space"] linearise = False - if cspace == "sRGB": - linearise = True - # set its file node to 'raw' as tx will be linearized - files_metadata[filepath]["color_space"] = "raw" + if do_maketx: + if cspace == "sRGB": + linearise = True + # set its file node to 'raw' as tx will be linearized + files_metadata[filepath]["color_space"] = "raw" source, mode, hash = self._process_texture( filepath, From 3efbfd52c355c106383d883df516df8d5bf051cd Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Wed, 2 Dec 2020 20:47:38 +0100 Subject: [PATCH 192/279] convert settings --- .../defaults/project_anatomy/dataflow.json | 55 --- .../defaults/project_settings/Ftrack.json | 25 ++ .../defaults/project_settings/attributes.json | 16 + .../ftrack/ftrack_custom_attributes.json | 171 +++---- .../ftrack/project_defaults.json | 18 - .../defaults/project_settings/global.json | 89 ++++ .../project_settings/global/creator.json | 8 - .../global/project_folder_structure.json | 22 - .../project_settings/global/sw_folders.json | 8 - .../project_settings/global/workfiles.json | 7 - .../premiere/asset_default.json | 5 - .../premiere/rules_tasks.json | 21 - .../defaults/project_settings/unreal.json | 6 + .../unreal/project_setup.json | 4 - .../system_settings/applications.json | 4 + .../defaults/system_settings/modules.json | 26 -- .../projects_schema/0_project_gui_schema.json | 4 + .../schema_project_ftrack.json | 81 ++++ .../schema_project_global.json | 419 +----------------- .../schema_project_unreal.json | 25 ++ .../schemas/schema_anatomy_attributes.json | 73 +++ .../{ => schemas}/schema_anatomy_imageio.json | 0 .../schemas/schema_global_publish.json | 399 +++++++++++++++++ .../schemas/schema_global_tools.json | 84 ++++ .../schemas/schema_maya_load.json | 1 - .../schemas/schema_maya_publish.json | 1 - .../schemas/schema_publish_gui_filter.json | 1 - .../schemas/schema_workfile_build.json | 1 - .../module_settings/schema_ftrack.json | 87 ---- 29 files changed, 891 insertions(+), 770 deletions(-) delete mode 100644 pype/settings/defaults/project_anatomy/dataflow.json create mode 100644 pype/settings/defaults/project_settings/attributes.json delete mode 100644 pype/settings/defaults/project_settings/ftrack/project_defaults.json delete mode 100644 pype/settings/defaults/project_settings/global/creator.json delete mode 100644 pype/settings/defaults/project_settings/global/project_folder_structure.json delete mode 100644 pype/settings/defaults/project_settings/global/sw_folders.json delete mode 100644 pype/settings/defaults/project_settings/global/workfiles.json delete mode 100644 pype/settings/defaults/project_settings/premiere/asset_default.json delete mode 100644 pype/settings/defaults/project_settings/premiere/rules_tasks.json create mode 100644 pype/settings/defaults/project_settings/unreal.json delete mode 100644 pype/settings/defaults/project_settings/unreal/project_setup.json create mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_unreal.json create mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_anatomy_attributes.json rename pype/tools/settings/settings/gui_schemas/projects_schema/{ => schemas}/schema_anatomy_imageio.json (100%) create mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_global_publish.json create mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_global_tools.json diff --git a/pype/settings/defaults/project_anatomy/dataflow.json b/pype/settings/defaults/project_anatomy/dataflow.json deleted file mode 100644 index d2f470b5bc..0000000000 --- a/pype/settings/defaults/project_anatomy/dataflow.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "nuke": { - "nodes": { - "connected": true, - "modifymetadata": { - "_id": "connect_metadata", - "_previous": "ENDING", - "metadata.set.pype_studio_name": "{PYPE_STUDIO_NAME}", - "metadata.set.avalon_project_name": "{AVALON_PROJECT}", - "metadata.set.avalon_project_code": "{PYPE_STUDIO_CODE}", - "metadata.set.avalon_asset_name": "{AVALON_ASSET}" - }, - "crop": { - "_id": "connect_crop", - "_previous": "connect_metadata", - "box": [ - "{metadata.crop.x}", - "{metadata.crop.y}", - "{metadata.crop.right}", - "{metadata.crop.top}" - ] - }, - "write": { - "render": { - "_id": "output_write", - "_previous": "connect_crop", - "file_type": "exr", - "datatype": "16 bit half", - "compression": "Zip (1 scanline)", - "autocrop": true, - "tile_color": "0xff0000ff", - "channels": "rgb" - }, - "prerender": { - "_id": "output_write", - "_previous": "connect_crop", - "file_type": "exr", - "datatype": "16 bit half", - "compression": "Zip (1 scanline)", - "autocrop": false, - "tile_color": "0xc9892aff", - "channels": "rgba" - }, - "still": { - "_previous": "connect_crop", - "channels": "rgba", - "file_type": "tiff", - "datatype": "16 bit", - "compression": "LZW", - "tile_color": "0x4145afff" - } - } - } - } -} diff --git a/pype/settings/defaults/project_settings/Ftrack.json b/pype/settings/defaults/project_settings/Ftrack.json index 7c9bb8ce0e..023b85cb3b 100644 --- a/pype/settings/defaults/project_settings/Ftrack.json +++ b/pype/settings/defaults/project_settings/Ftrack.json @@ -2,6 +2,31 @@ "ftrack_actions_path": [], "ftrack_events_path": [], "events": { + "sync_to_avalon": { + "enabled": true, + "statuses_name_change": [ + "ready", + "not ready" + ] + }, + "push_frame_values_to_task": { + "enabled": true, + "interest_entity_types": [ + "shot", + "asset build" + ], + "interest_attributess": [ + "frameStart", + "frameEnd" + ] + }, + "thumbnail_updates": { + "enabled": true, + "levels": 2 + }, + "user_assignment": { + "enabled": true + }, "status_update": { "enabled": true, "mapping": { diff --git a/pype/settings/defaults/project_settings/attributes.json b/pype/settings/defaults/project_settings/attributes.json new file mode 100644 index 0000000000..df586c105a --- /dev/null +++ b/pype/settings/defaults/project_settings/attributes.json @@ -0,0 +1,16 @@ +{ + "fps": 25, + "frameStart": 1001, + "frameEnd": 1001, + "clipIn": 1, + "clipOut": 1, + "handleStart": 0, + "handleEnd": 0, + "resolutionWidth": 1920, + "resolutionHeight": 1080, + "pixelAspect": 1, + "applications": [ + "maya_2019", + "nuke_12.2" + ] +} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/ftrack/ftrack_custom_attributes.json b/pype/settings/defaults/project_settings/ftrack/ftrack_custom_attributes.json index 371be3b8d8..c4e204f716 100644 --- a/pype/settings/defaults/project_settings/ftrack/ftrack_custom_attributes.json +++ b/pype/settings/defaults/project_settings/ftrack/ftrack_custom_attributes.json @@ -1,109 +1,66 @@ -[{ - "label": "FPS", - "key": "fps", - "type": "number", - "is_hierarchical": true, - "group": "avalon", - "write_security_role": ["ALL"], - "read_security_role": ["ALL"], - "default": null, - "config": { - "isdecimal": true +{ + "show": { + "avalon_auto_sync": { + "default": null, + "write_security_role": [], + "read_security_role": [] + }, + "library_project": { + "default": null, + "write_security_role": [], + "read_security_role": [] + } + }, + "is_hierarchical": { + "fps": { + "default": null, + "write_security_role": [], + "read_security_role": [] + }, + "clipIn": { + "default": null, + "write_security_role": [], + "read_security_role": [] + }, + "clipOut": { + "default": null, + "write_security_role": [], + "read_security_role": [] + }, + "frameStart": { + "default": null, + "write_security_role": [], + "read_security_role": [] + }, + "frameEnd": { + "default": null, + "write_security_role": [], + "read_security_role": [] + }, + "resolutionWidth": { + "default": null, + "write_security_role": [], + "read_security_role": [] + }, + "resolutionHeight": { + "default": null, + "write_security_role": [], + "read_security_role": [] + }, + "pixelAspect": { + "default": null, + "write_security_role": [], + "read_security_role": [] + }, + "handleStart": { + "default": null, + "write_security_role": [], + "read_security_role": [] + }, + "handleEnd": { + "default": null, + "write_security_role": [], + "read_security_role": [] + } } -}, { - "label": "Avalon auto-sync", - "key": "avalon_auto_sync", - "type": "boolean", - "entity_type": "show", - "group": "avalon", - "write_security_role": ["API", "Administrator"], - "read_security_role": ["API", "Administrator"] -}, { - "label": "Intent", - "key": "intent", - "type": "enumerator", - "entity_type": "assetversion", - "group": "avalon", - "config": { - "multiselect": false, - "data": [ - {"test": "Test"}, - {"wip": "WIP"}, - {"final": "Final"} - ] - } -}, { - "label": "Library Project", - "key": "library_project", - "type": "boolean", - "entity_type": "show", - "group": "avalon", - "write_security_role": ["API", "Administrator"], - "read_security_role": ["API", "Administrator"] -}, { - "label": "Clip in", - "key": "clipIn", - "type": "number", - "is_hierarchical": true, - "group": "avalon", - "default": null -}, { - "label": "Clip out", - "key": "clipOut", - "type": "number", - "is_hierarchical": true, - "group": "avalon", - "default": null -}, { - "label": "Frame start", - "key": "frameStart", - "type": "number", - "is_hierarchical": true, - "group": "avalon", - "default": null -}, { - "label": "Frame end", - "key": "frameEnd", - "type": "number", - "is_hierarchical": true, - "group": "avalon", - "default": null -}, { - "label": "Resolution Width", - "key": "resolutionWidth", - "type": "number", - "is_hierarchical": true, - "group": "avalon", - "default": null -}, { - "label": "Resolution Height", - "key": "resolutionHeight", - "type": "number", - "is_hierarchical": true, - "group": "avalon", - "default": null -}, { - "label": "Pixel aspect", - "key": "pixelAspect", - "type": "number", - "is_hierarchical": true, - "group": "avalon", - "config": { - "isdecimal": true - } -}, { - "label": "Frame handles start", - "key": "handleStart", - "type": "number", - "is_hierarchical": true, - "group": "avalon", - "default": null -}, { - "label": "Frame handles end", - "key": "handleEnd", - "type": "number", - "is_hierarchical": true, - "group": "avalon", - "default": null } -] diff --git a/pype/settings/defaults/project_settings/ftrack/project_defaults.json b/pype/settings/defaults/project_settings/ftrack/project_defaults.json deleted file mode 100644 index a4e3aa3362..0000000000 --- a/pype/settings/defaults/project_settings/ftrack/project_defaults.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "fps": 25, - "frameStart": 1001, - "frameEnd": 1100, - "clipIn": 1001, - "clipOut": 1100, - "handleStart": 10, - "handleEnd": 10, - - "resolutionHeight": 1080, - "resolutionWidth": 1920, - "pixelAspect": 1.0, - "applications": [ - "maya_2019", "nuke_11.3", "nukex_11.3", "nukestudio_11.3", "deadline" - ], - "tools_env": [], - "avalon_auto_sync": true -} diff --git a/pype/settings/defaults/project_settings/global.json b/pype/settings/defaults/project_settings/global.json index dd379b6180..407dd23593 100644 --- a/pype/settings/defaults/project_settings/global.json +++ b/pype/settings/defaults/project_settings/global.json @@ -111,5 +111,94 @@ ] } } + }, + "tools": { + "Creator": { + "families_smart_select": { + "Render": [ + "light", + "render" + ], + "Model": [ + "model" + ], + "Layout": [ + "layout" + ], + "Look": [ + "look" + ], + "Rig": [ + "rigging", + "rig" + ] + } + }, + "Workfiles": { + "last_workfile_on_startup": { + "profiles": [ + { + "hosts": [], + "tasks": [], + "enabled": true + } + ] + }, + "sw_folders": { + "compositing": [ + "nuke", + "ae" + ], + "modeling": [ + "maya", + "blender", + "zbrush" + ], + "lookdev": [ + "substance", + "textures" + ] + } + } + }, + "attributes": { + "fps": 25, + "frameStart": 1001, + "frameEnd": 1001, + "clipIn": 1, + "clipOut": 1, + "handleStart": 0, + "handleEnd": 0, + "resolutionWidth": 1920, + "resolutionHeight": 1008, + "pixelAspect": 1, + "applications": [ + "maya_2020", + "nuke_12.2", + "hiero_12.2", + "blender_2.91" + ] + }, + "project_folder_structure": { + "__project_root__": { + "prod": {}, + "resources": { + "footage": { + "plates": {}, + "offline": {} + }, + "audio": {}, + "art_dept": {} + }, + "editorial": {}, + "assets[ftrack.Library]": { + "characters[ftrack]": {}, + "locations[ftrack]": {} + }, + "shots[ftrack.Sequence]": { + "scripts": {}, + "editorial[ftrack.Folder]": {} + } + } } } \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/global/creator.json b/pype/settings/defaults/project_settings/global/creator.json deleted file mode 100644 index d14e779f01..0000000000 --- a/pype/settings/defaults/project_settings/global/creator.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "Model": ["model"], - "Render Globals": ["light", "render"], - "Layout": ["layout"], - "Set Dress": ["setdress"], - "Look": ["look"], - "Rig": ["rigging"] -} diff --git a/pype/settings/defaults/project_settings/global/project_folder_structure.json b/pype/settings/defaults/project_settings/global/project_folder_structure.json deleted file mode 100644 index 83bd5f12a9..0000000000 --- a/pype/settings/defaults/project_settings/global/project_folder_structure.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "__project_root__": { - "prod" : {}, - "resources" : { - "footage": { - "plates": {}, - "offline": {} - }, - "audio": {}, - "art_dept": {} - }, - "editorial" : {}, - "assets[ftrack.Library]": { - "characters[ftrack]": {}, - "locations[ftrack]": {} - }, - "shots[ftrack.Sequence]": { - "scripts": {}, - "editorial[ftrack.Folder]": {} - } - } -} diff --git a/pype/settings/defaults/project_settings/global/sw_folders.json b/pype/settings/defaults/project_settings/global/sw_folders.json deleted file mode 100644 index a154935dce..0000000000 --- a/pype/settings/defaults/project_settings/global/sw_folders.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "compositing": ["nuke", "ae"], - "modeling": ["maya", "app2"], - "lookdev": ["substance"], - "animation": [], - "lighting": [], - "rigging": [] -} diff --git a/pype/settings/defaults/project_settings/global/workfiles.json b/pype/settings/defaults/project_settings/global/workfiles.json deleted file mode 100644 index 393b2e3c10..0000000000 --- a/pype/settings/defaults/project_settings/global/workfiles.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "last_workfile_on_startup": [ - { - "enabled": false - } - ] -} diff --git a/pype/settings/defaults/project_settings/premiere/asset_default.json b/pype/settings/defaults/project_settings/premiere/asset_default.json deleted file mode 100644 index 84d2bde3d8..0000000000 --- a/pype/settings/defaults/project_settings/premiere/asset_default.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "frameStart": 1001, - "handleStart": 0, - "handleEnd": 0 -} diff --git a/pype/settings/defaults/project_settings/premiere/rules_tasks.json b/pype/settings/defaults/project_settings/premiere/rules_tasks.json deleted file mode 100644 index 333c9cd70b..0000000000 --- a/pype/settings/defaults/project_settings/premiere/rules_tasks.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "defaultTasks": ["Layout", "Animation"], - "taskToSubsets": { - "Layout": ["reference", "audio"], - "Animation": ["audio"] - }, - "subsetToRepresentations": { - "reference": { - "preset": "h264", - "representation": "mp4" - }, - "thumbnail": { - "preset": "jpeg_thumb", - "representation": "jpg" - }, - "audio": { - "preset": "48khz", - "representation": "wav" - } - } -} diff --git a/pype/settings/defaults/project_settings/unreal.json b/pype/settings/defaults/project_settings/unreal.json new file mode 100644 index 0000000000..46b9ca2a18 --- /dev/null +++ b/pype/settings/defaults/project_settings/unreal.json @@ -0,0 +1,6 @@ +{ + "project_setup": { + "dev_mode": true, + "install_unreal_python_engine": false + } +} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/unreal/project_setup.json b/pype/settings/defaults/project_settings/unreal/project_setup.json deleted file mode 100644 index 8a4dffc526..0000000000 --- a/pype/settings/defaults/project_settings/unreal/project_setup.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "dev_mode": false, - "install_unreal_python_engine": false -} diff --git a/pype/settings/defaults/system_settings/applications.json b/pype/settings/defaults/system_settings/applications.json index b0e9635ca8..1393b94ff5 100644 --- a/pype/settings/defaults/system_settings/applications.json +++ b/pype/settings/defaults/system_settings/applications.json @@ -944,6 +944,10 @@ [ "C:\\Program Files\\TVPaint Developpement\\TVPaint Animation 11 (64bits)\\TVPaint Animation 11 (64bits).exe", "" + ], + [ + "C:\\Program Files\\TVPaint Developpement\\TVPaint Animation 11 Pro (64bits) (DEMO)\\TVPaint Animation 11 Pro (64bits) (DEMO).exe", + "" ] ], "darwin": [], diff --git a/pype/settings/defaults/system_settings/modules.json b/pype/settings/defaults/system_settings/modules.json index 386e37b246..cf2372dece 100644 --- a/pype/settings/defaults/system_settings/modules.json +++ b/pype/settings/defaults/system_settings/modules.json @@ -27,32 +27,6 @@ "ftrack_events_path": [], "FTRACK_EVENTS_MONGO_DB": "pype", "FTRACK_EVENTS_MONGO_COL": "ftrack_events", - "events": { - "sync_to_avalon": { - "enabled": true, - "statuses_name_change": [ - "not ready", - "ready" - ] - }, - "push_frame_values_to_task": { - "enabled": true, - "interest_entity_types": [ - "shot" - ], - "interest_attributess": [ - "frameStart", - "frameEnd" - ] - }, - "thumbnail_updates": { - "enabled": true, - "levels": 2 - }, - "user_assignment": { - "enabled": true - } - }, "intent": { "items": { "-": "-", diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json b/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json index da949699ad..06937778d6 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json @@ -54,6 +54,10 @@ { "type": "schema", "name": "schema_project_standalonepublisher" + }, + { + "type": "schema", + "name": "schema_project_unreal" } ] } diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json index a7c835081a..3b784accc1 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json @@ -33,6 +33,87 @@ "key": "events", "label": "Server Events", "children": [ + { + "type": "dict", + "key": "sync_to_avalon", + "label": "Sync to avalon", + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "label", + "label": "Allow name and hierarchy change only if following statuses are on all children tasks" + }, + { + "type": "list", + "key": "statuses_name_change", + "label": "Statuses", + "object_type": { + "type": "text", + "multiline": false + } + } + ] + }, + { + "type": "dict", + "key": "push_frame_values_to_task", + "label": "Sync Hierarchical and Entity Attributes", + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "list", + "key": "interest_entity_types", + "label": "Entity types of interest", + "object_type": { + "type": "text", + "multiline": false + } + }, { + "type": "list", + "key": "interest_attributess", + "label": "Attributes to sync", + "object_type": { + "type": "text", + "multiline": false + } + }] + }, + { + "type": "dict", + "key": "thumbnail_updates", + "label": "Update Hierarchy thumbnails", + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + },{ + "type": "label", + "label": "Push thumbnail from version, up through multiple hierarchy levels." + },{ + "type": "number", + "key": "levels", + "label": "Levels" + }] + }, + { + "type": "dict", + "key": "user_assignment", + "label": "Run script on user assignments", + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }] + }, { "type": "dict", "key": "status_update", diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_global.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_global.json index 6fdc6a23a5..d78d430e9b 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_global.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_global.json @@ -6,403 +6,26 @@ "is_file": true, "children": [ { - "type": "dict", - "collapsable": true, - "key": "publish", - "label": "Publish plugins", - "is_file": true, + "type": "schema", + "name": "schema_global_publish" + }, + { + "type": "schema", + "name": "schema_global_tools" + }, + { + "type": "schema", + "name": "schema_anatomy_attributes" + }, + { + "type": "collapsible-wrap", + "label": "Project Folder Structure", "children": [ - { - "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "IntegrateMasterVersion", - "label": "IntegrateMasterVersion", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }] - }, - { - "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "ExtractJpegEXR", - "label": "ExtractJpegEXR", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, - { - "type": "dict", - "key": "ffmpeg_args", - "children": [ - { - "type": "list", - "object_type": "text", - "key": "input", - "label": "FFmpeg input arguments" - }, - { - "type": "list", - "object_type": "text", - "key": "output", - "label": "FFmpeg output arguments" - }] - }] - }, - { - "type": "dict", - "collapsable": true, - "key": "ExtractReview", - "label": "ExtractReview", - "checkbox_key": "enabled", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, - { - "type": "list", - "key": "profiles", - "label": "Profiles", - "object_type": - { - "type": "dict", - "children": [ - { - "key": "families", - "label": "Families", - "type": "list", - "object_type": "text" - }, - { - "key": "hosts", - "label": "Hosts", - "type": "list", - "object_type": "text" - }, - { - "type": "splitter" - }, - { - "key": "outputs", - "label": "Output Definitions", - "type": "dict-modifiable", - "highlight_content": true, - "object_type": - { - "type": "dict", - "children": [ - { - "key": "ext", - "label": "Output extension", - "type": "text" - }, - { - "key": "tags", - "label": "Tags", - "type": "enum", - "multiselection": true, - "enum_items": [ - { - "burnin": "Add burnins" - }, - { - "ftrackreview": "Add to Ftrack" - }, - { - "delete": "Delete output" - }, - { - "slate-frame": "Add slate frame" - }, - { - "no-hnadles": "Skip handle frames" - }] - }, - { - "key": "ffmpeg_args", - "label": "FFmpeg arguments", - "type": "dict", - "highlight_content": true, - "children": [ - { - "key": "video_filters", - "label": "Video filters", - "type": "list", - "object_type": "text" - }, - { - "type": "splitter" - }, - { - "key": "audio_filters", - "label": "Audio filters", - "type": "list", - "object_type": "text" - }, - { - "type": "splitter" - }, - { - "key": "input", - "label": "Input arguments", - "type": "list", - "object_type": "text" - }, - { - "type": "splitter" - }, - { - "key": "output", - "label": "Output arguments", - "type": "list", - "object_type": "text" - }] - }, - { - "key": "filter", - "label": "Additional output filtering", - "type": "dict", - "highlight_content": true, - "children": [ - { - "key": "families", - "label": "Families", - "type": "list", - "object_type": "text" - }] - }] - } - }] - } - }] - }, - { - "type": "dict", - "collapsable": true, - "key": "ExtractBurnin", - "label": "ExtractBurnin", - "checkbox_key": "enabled", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, - { - "type": "dict", - "collapsable": true, - "key": "options", - "label": "Burnin formating options", - "children": [ - { - "type": "number", - "key": "font_size", - "label": "Font size" - }, - { - "type": "number", - "key": "opacity", - "label": "Font opacity" - }, - { - "type": "number", - "key": "bg_opacity", - "label": "Background opacity" - }, - { - "type": "number", - "key": "x_offset", - "label": "X Offset" - }, - { - "type": "number", - "key": "y_offset", - "label": "Y Offset" - }, - { - "type": "number", - "key": "bg_padding", - "label": "Padding aroung text" - }, - { - "type": "splitter" - }] - }, - - { - "type": "list", - "key": "profiles", - "label": "Profiles", - "object_type": - { - "type": "dict", - "children": [ - { - "key": "families", - "label": "Families", - "type": "list", - "object_type": "text" - }, - { - "key": "hosts", - "label": "Hosts", - "type": "list", - "object_type": "text" - }, - { - "type": "splitter" - }, - { - "key": "burnins", - "label": "Burnins", - "type": "dict-modifiable", - "highlight_content": true, - "collapsable": false, - "object_type": - { - "type": "dict", - "children": [ - { - "key": "TOP_LEFT", - "label": "Top Left", - "type": "text" - }, - { - "key": "TOP_CENTERED", - "label": "Top Centered", - "type": "text" - }, - { - "key": "TOP_RIGHT", - "label": "top Right", - "type": "text" - }, - { - "key": "BOTTOM_LEFT", - "label": "Bottom Left", - "type": "text" - }, - { - "key": "BOTTOM_CENTERED", - "label": "Bottom Centered", - "type": "text" - }, - { - "key": "BOTTOM_RIGHT", - "label": "BottomRight", - "type": "text" - }] - } - }] - } - } - ] - }, - { - "type": "dict", - "collapsable": true, - "key": "IntegrateAssetNew", - "label": "IntegrateAssetNew", - "is_group": true, - "children": [ - { - "type": "raw-json", - "key": "template_name_profiles", - "label": "template_name_profiles" - }] - }, - { - "type": "dict", - "collapsable": true, - "key": "ProcessSubmittedJobOnFarm", - "label": "ProcessSubmittedJobOnFarm", - "checkbox_key": "enabled", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, - { - "type": "text", - "key": "deadline_department", - "label": "Deadline department" - }, - { - "type": "text", - "key": "deadline_pool", - "label": "Deadline Pool" - }, - { - "type": "text", - "key": "deadline_group", - "label": "Deadline Group" - }, - { - "type": "text", - "key": "deadline_chunk_size", - "label": "Deadline Chunk Size" - }, - { - "type": "text", - "key": "deadline_priority", - "label": "Deadline Priotity" - }, - { - "type": "dict", - "key": "aov_filter", - "label": "Reviewable subsets filter", - "children": [ - { - "type": "list", - "key": "maya", - "label": "Maya", - "object_type": - { - "type": "text" - } - }, - { - "type": "list", - "key": "nuke", - "label": "Nuke", - "object_type": - { - "type": "text" - } - }, - { - "type": "list", - "key": "aftereffects", - "label": "After Effects", - "object_type": - { - "type": "text" - } - }, - { - "type": "list", - "key": "celaction", - "label": "Celaction", - "object_type": - { - "type": "text" - } - }] - }] - }] - }] + { + "type": "raw-json", + "key": "project_folder_structure", + "label": "" + }] + } + ] } diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_unreal.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_unreal.json new file mode 100644 index 0000000000..63cfdec639 --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_unreal.json @@ -0,0 +1,25 @@ +{ + "type": "dict", + "collapsable": true, + "key": "unreal", + "label": "Unreal Engine", + "is_file": true, + "children": [ + { + "type": "dict", + "collapsable": true, + "key": "project_setup", + "label": "Project Setup", + "children": [ + { + "type": "boolean", + "key": "dev_mode", + "label": "Dev mode" + }, + { + "type": "boolean", + "key": "install_unreal_python_engine", + "label": "Install unreal python engine" + }] + }] +} diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_anatomy_attributes.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_anatomy_attributes.json new file mode 100644 index 0000000000..c56e4432e3 --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_anatomy_attributes.json @@ -0,0 +1,73 @@ +{ + "type": "dict", + "collapsable": true, + "key": "attributes", + "label": "Project Attribute Defaults", + "is_file": true, + "children": [ + { + "type": "number", + "key": "fps", + "label": "Frame Rate" + }, + { + "type": "number", + "key": "frameStart", + "label": "Frame Start" + }, + { + "type": "number", + "key": "frameEnd", + "label": "Frame End" + }, + { + "type": "number", + "key": "clipIn", + "label": "Clip In" + }, + { + "type": "number", + "key": "clipOut", + "label": "Clip Out" + }, + { + "type": "number", + "key": "handleStart", + "label": "Handle Start" + }, + { + "type": "number", + "key": "handleEnd", + "label": "Handle End" + }, + { + "type": "number", + "key": "resolutionWidth", + "label": "Resolution Width" + }, + { + "type": "number", + "key": "resolutionHeight", + "label": "Resolution Height" + }, + { + "type": "number", + "key": "pixelAspect", + "label": "Pixel Aspect Ratio" + }, + { + "type": "enum", + "key": "applications", + "label": "Applications", + "multiselection": true, + "enum_items": [ + {"maya_2020" : "Maya 2020"}, + {"nuke_12.2": "Nuke 12.2"}, + {"hiero_12.2": "Hiero 12.2"}, + {"houdini_18": "Houdini 18"}, + {"blender_2.91": "Blender 2.91"}, + {"aftereffects_2021": "After Effects 2021"} + ] + } + ] +} diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_anatomy_imageio.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_anatomy_imageio.json similarity index 100% rename from pype/tools/settings/settings/gui_schemas/projects_schema/schema_anatomy_imageio.json rename to pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_anatomy_imageio.json diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_global_publish.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_global_publish.json new file mode 100644 index 0000000000..86c6f2963e --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_global_publish.json @@ -0,0 +1,399 @@ +{ + "type": "dict", + "collapsable": true, + "key": "publish", + "label": "Publish plugins", + "children": [ + { + "type": "dict", + "collapsable": true, + "checkbox_key": "enabled", + "key": "IntegrateMasterVersion", + "label": "IntegrateMasterVersion", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }] + }, + { + "type": "dict", + "collapsable": true, + "checkbox_key": "enabled", + "key": "ExtractJpegEXR", + "label": "ExtractJpegEXR", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "dict", + "key": "ffmpeg_args", + "children": [ + { + "type": "list", + "object_type": "text", + "key": "input", + "label": "FFmpeg input arguments" + }, + { + "type": "list", + "object_type": "text", + "key": "output", + "label": "FFmpeg output arguments" + }] + }] + }, + { + "type": "dict", + "collapsable": true, + "key": "ExtractReview", + "label": "ExtractReview", + "checkbox_key": "enabled", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "list", + "key": "profiles", + "label": "Profiles", + "object_type": + { + "type": "dict", + "children": [ + { + "key": "families", + "label": "Families", + "type": "list", + "object_type": "text" + }, + { + "key": "hosts", + "label": "Hosts", + "type": "list", + "object_type": "text" + }, + { + "type": "splitter" + }, + { + "key": "outputs", + "label": "Output Definitions", + "type": "dict-modifiable", + "highlight_content": true, + "object_type": + { + "type": "dict", + "children": [ + { + "key": "ext", + "label": "Output extension", + "type": "text" + }, + { + "key": "tags", + "label": "Tags", + "type": "enum", + "multiselection": true, + "enum_items": [ + { + "burnin": "Add burnins" + }, + { + "ftrackreview": "Add to Ftrack" + }, + { + "delete": "Delete output" + }, + { + "slate-frame": "Add slate frame" + }, + { + "no-hnadles": "Skip handle frames" + }] + }, + { + "key": "ffmpeg_args", + "label": "FFmpeg arguments", + "type": "dict", + "highlight_content": true, + "children": [ + { + "key": "video_filters", + "label": "Video filters", + "type": "list", + "object_type": "text" + }, + { + "type": "splitter" + }, + { + "key": "audio_filters", + "label": "Audio filters", + "type": "list", + "object_type": "text" + }, + { + "type": "splitter" + }, + { + "key": "input", + "label": "Input arguments", + "type": "list", + "object_type": "text" + }, + { + "type": "splitter" + }, + { + "key": "output", + "label": "Output arguments", + "type": "list", + "object_type": "text" + }] + }, + { + "key": "filter", + "label": "Additional output filtering", + "type": "dict", + "highlight_content": true, + "children": [ + { + "key": "families", + "label": "Families", + "type": "list", + "object_type": "text" + }] + }] + } + }] + } + }] + }, + { + "type": "dict", + "collapsable": true, + "key": "ExtractBurnin", + "label": "ExtractBurnin", + "checkbox_key": "enabled", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "dict", + "collapsable": true, + "key": "options", + "label": "Burnin formating options", + "children": [ + { + "type": "number", + "key": "font_size", + "label": "Font size" + }, + { + "type": "number", + "key": "opacity", + "label": "Font opacity" + }, + { + "type": "number", + "key": "bg_opacity", + "label": "Background opacity" + }, + { + "type": "number", + "key": "x_offset", + "label": "X Offset" + }, + { + "type": "number", + "key": "y_offset", + "label": "Y Offset" + }, + { + "type": "number", + "key": "bg_padding", + "label": "Padding aroung text" + }, + { + "type": "splitter" + }] + }, + + { + "type": "list", + "key": "profiles", + "label": "Profiles", + "object_type": + { + "type": "dict", + "children": [ + { + "key": "families", + "label": "Families", + "type": "list", + "object_type": "text" + }, + { + "key": "hosts", + "label": "Hosts", + "type": "list", + "object_type": "text" + }, + { + "type": "splitter" + }, + { + "key": "burnins", + "label": "Burnins", + "type": "dict-modifiable", + "highlight_content": true, + "collapsable": false, + "object_type": + { + "type": "dict", + "children": [ + { + "key": "TOP_LEFT", + "label": "Top Left", + "type": "text" + }, + { + "key": "TOP_CENTERED", + "label": "Top Centered", + "type": "text" + }, + { + "key": "TOP_RIGHT", + "label": "top Right", + "type": "text" + }, + { + "key": "BOTTOM_LEFT", + "label": "Bottom Left", + "type": "text" + }, + { + "key": "BOTTOM_CENTERED", + "label": "Bottom Centered", + "type": "text" + }, + { + "key": "BOTTOM_RIGHT", + "label": "BottomRight", + "type": "text" + }] + } + }] + } + } + ] + }, + { + "type": "dict", + "collapsable": true, + "key": "IntegrateAssetNew", + "label": "IntegrateAssetNew", + "is_group": true, + "children": [ + { + "type": "raw-json", + "key": "template_name_profiles", + "label": "template_name_profiles" + }] + }, + { + "type": "dict", + "collapsable": true, + "key": "ProcessSubmittedJobOnFarm", + "label": "ProcessSubmittedJobOnFarm", + "checkbox_key": "enabled", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "text", + "key": "deadline_department", + "label": "Deadline department" + }, + { + "type": "text", + "key": "deadline_pool", + "label": "Deadline Pool" + }, + { + "type": "text", + "key": "deadline_group", + "label": "Deadline Group" + }, + { + "type": "text", + "key": "deadline_chunk_size", + "label": "Deadline Chunk Size" + }, + { + "type": "text", + "key": "deadline_priority", + "label": "Deadline Priotity" + }, + { + "type": "dict", + "key": "aov_filter", + "label": "Reviewable subsets filter", + "children": [ + { + "type": "list", + "key": "maya", + "label": "Maya", + "object_type": + { + "type": "text" + } + }, + { + "type": "list", + "key": "nuke", + "label": "Nuke", + "object_type": + { + "type": "text" + } + }, + { + "type": "list", + "key": "aftereffects", + "label": "After Effects", + "object_type": + { + "type": "text" + } + }, + { + "type": "list", + "key": "celaction", + "label": "Celaction", + "object_type": + { + "type": "text" + } + }] + }] + }] +} diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_global_tools.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_global_tools.json new file mode 100644 index 0000000000..5a19e4827d --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_global_tools.json @@ -0,0 +1,84 @@ +{ + "type": "dict", + "collapsable": true, + "key": "tools", + "label": "Tools", + "children": [ + { + "type": "dict", + "collapsable": true, + "key": "Creator", + "label": "Creator", + "children": [ + { + "type": "dict-modifiable", + "collapsable": false, + "key": "families_smart_select", + "label": "Families smart select", + "object_type":{ + "type": "list", + "object_type": "text" + } + }] + }, + { + "type": "dict", + "collapsable": true, + "key": "Workfiles", + "label": "Workfiles", + "children": [ + { + "type": "dict", + "collapsable": true, + "key": "last_workfile_on_startup", + "label": "Open last workfiles on launch", + "checkbox_key": "enabled", + "is_group": true, + "children": [ + { + "type": "list", + "key": "profiles", + "label": "Profiles", + "object_type": + { + "type": "dict", + "children": [ + { + "key": "hosts", + "label": "Hosts", + "type": "list", + "object_type": "text" + }, + { + "key": "tasks", + "label": "Tasks", + "type": "list", + "object_type": "text" + }, + { + "type": "splitter" + }, + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + } + ] + } + } + ] + }, + { + "type": "dict-modifiable", + "collapsable": true, + "key": "sw_folders", + "label": "Extra task folders", + "is_group": true, + "object_type":{ + "type": "list", + "object_type": "text" + } + } + ] + }] +} diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_load.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_load.json index 0b96e63124..28750eb795 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_load.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_load.json @@ -3,7 +3,6 @@ "collapsable": true, "key": "load", "label": "Loader plugins", - "is_file": true, "children": [ { "type": "dict", diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_publish.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_publish.json index 44972cad21..33d0a06d2c 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_publish.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_maya_publish.json @@ -3,7 +3,6 @@ "collapsable": true, "key": "publish", "label": "Publish plugins", - "is_file": true, "children": [ { "type": "label", diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_publish_gui_filter.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_publish_gui_filter.json index f2385996eb..2acb5730a3 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_publish_gui_filter.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_publish_gui_filter.json @@ -3,7 +3,6 @@ "collapsable": true, "key": "filters", "label": "Publish GUI Filters", - "is_file": true, "object_type": { "type": "raw-json", diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_workfile_build.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_workfile_build.json index d8d5b0b09b..054f009ad4 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_workfile_build.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_workfile_build.json @@ -3,7 +3,6 @@ "collapsable": true, "key": "workfile_build", "label": "Workfile Build Settings", - "is_group": true, "children": [{ "type": "list", "key": "profiles", diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json b/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json index 8dd219e98e..92fddc6298 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json @@ -50,93 +50,6 @@ "key": "FTRACK_EVENTS_MONGO_COL", "label": "Events Mongo Collection" }, - { - "type": "dict", - "key": "events", - "label": "Server Events", - "children": [{ - "type": "dict", - "key": "sync_to_avalon", - "label": "Sync to avalon", - "checkbox_key": "enabled", - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, - { - "type": "label", - "label": "Allow name and hierarchy change only if following statuses are on all children tasks" - }, - { - "type": "list", - "key": "statuses_name_change", - "label": "Statuses", - "object_type": { - "type": "text", - "multiline": false - } - } - ] - }, - { - "type": "dict", - "key": "push_frame_values_to_task", - "label": "Sync Hierarchical and Entity Attributes", - "checkbox_key": "enabled", - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "list", - "key": "interest_entity_types", - "label": "Entity types of interest", - "object_type": { - "type": "text", - "multiline": false - } - }, { - "type": "list", - "key": "interest_attributess", - "label": "Attributes to sync", - "object_type": { - "type": "text", - "multiline": false - } - }] - }, - { - "type": "dict", - "key": "thumbnail_updates", - "label": "Update Hierarchy thumbnails", - "checkbox_key": "enabled", - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - },{ - "type": "label", - "label": "Push thumbnail from version, up through multiple hierarchy levels." - },{ - "type": "number", - "key": "levels", - "label": "Levels" - }] - }, - { - "type": "dict", - "key": "user_assignment", - "label": "Run script on user assignments", - "checkbox_key": "enabled", - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }] - } - ] - }, { "type": "splitter" }, From 768be9645a7cad7efdba49c070e67ddb95698dc7 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Wed, 2 Dec 2020 20:56:06 +0100 Subject: [PATCH 193/279] move attributes to anatomy --- .../defaults/environments/avalon.json | 16 ---------- .../defaults/environments/global.json | 32 ------------------- .../defaults/project_anatomy/attributes.json | 13 ++++++++ .../defaults/project_settings/global.json | 18 ----------- .../projects_schema/0_project_gui_schema.json | 7 +++- .../schema_project_global.json | 5 +-- .../schemas/schema_anatomy_attributes.json | 2 +- 7 files changed, 21 insertions(+), 72 deletions(-) delete mode 100644 pype/settings/defaults/environments/avalon.json delete mode 100644 pype/settings/defaults/environments/global.json create mode 100644 pype/settings/defaults/project_anatomy/attributes.json diff --git a/pype/settings/defaults/environments/avalon.json b/pype/settings/defaults/environments/avalon.json deleted file mode 100644 index 832ba07e71..0000000000 --- a/pype/settings/defaults/environments/avalon.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "AVALON_CONFIG": "pype", - "AVALON_PROJECTS": "{PYPE_PROJECTS_PATH}", - "AVALON_USERNAME": "avalon", - "AVALON_PASSWORD": "secret", - "AVALON_DEBUG": "1", - "AVALON_MONGO": "mongodb://localhost:2707", - "AVALON_DB": "avalon", - "AVALON_DB_DATA": "{PYPE_SETUP_PATH}/../mongo_db_data", - "AVALON_EARLY_ADOPTER": "1", - "AVALON_SCHEMA": "{PYPE_MODULE_ROOT}/schema", - "AVALON_LOCATION": "http://127.0.0.1", - "AVALON_LABEL": "Pype", - "AVALON_TIMEOUT": "1000", - "AVALON_THUMBNAIL_ROOT": "" -} diff --git a/pype/settings/defaults/environments/global.json b/pype/settings/defaults/environments/global.json deleted file mode 100644 index 717e337db8..0000000000 --- a/pype/settings/defaults/environments/global.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "PYPE_STUDIO_NAME": "Studio Name", - "PYPE_STUDIO_CODE": "stu", - "PYPE_APP_ROOT": "{PYPE_SETUP_PATH}/pypeapp", - "PYPE_MODULE_ROOT": "{PYPE_SETUP_PATH}/repos/pype", - "PYPE_PROJECT_PLUGINS": "", - "STUDIO_SOFT": "{PYP_SETUP_ROOT}/soft", - "FFMPEG_PATH": { - "windows": "{VIRTUAL_ENV}/localized/ffmpeg_exec/windows/bin;{PYPE_SETUP_PATH}/vendor/bin/ffmpeg_exec/windows/bin", - "darwin": "{VIRTUAL_ENV}/localized/ffmpeg_exec/darwin/bin:{PYPE_SETUP_PATH}/vendor/bin/ffmpeg_exec/darwin/bin", - "linux": "{VIRTUAL_ENV}/localized/ffmpeg_exec/linux:{PYPE_SETUP_PATH}/vendor/bin/ffmpeg_exec/linux" - }, - "PATH": [ - "{PYPE_CONFIG}/launchers", - "{PYPE_APP_ROOT}", - "{FFMPEG_PATH}", - "{PATH}" - ], - "PYPE_OCIO_CONFIG": "{STUDIO_SOFT}/OpenColorIO-Configs", - "PYTHONPATH": { - "windows": "{VIRTUAL_ENV}/Lib/site-packages;{PYPE_MODULE_ROOT}/pype/tools;{PYTHONPATH}", - "linux": "{VIRTUAL_ENV}/lib/python{PYTHON_VERSION}/site-packages:{PYPE_MODULE_ROOT}/pype/tools:{PYTHONPATH}", - "darwin": "{VIRTUAL_ENV}/lib/python{PYTHON_VERSION}/site-packages:{PYPE_MODULE_ROOT}/pype/tools:{PYTHONPATH}" - }, - "PYPE_PROJECT_CONFIGS": "{PYPE_SETUP_PATH}/../studio-project-configs", - "PYPE_PYTHON_EXE": { - "windows": "{VIRTUAL_ENV}/Scripts/python.exe", - "linux": "{VIRTUAL_ENV}/Scripts/python", - "darwin": "{VIRTUAL_ENV}/bin/python" - }, - "PYBLISH_GUI": "pyblish_pype" -} diff --git a/pype/settings/defaults/project_anatomy/attributes.json b/pype/settings/defaults/project_anatomy/attributes.json new file mode 100644 index 0000000000..fbf0218999 --- /dev/null +++ b/pype/settings/defaults/project_anatomy/attributes.json @@ -0,0 +1,13 @@ +{ + "fps": 25, + "frameStart": 1001, + "frameEnd": 1001, + "clipIn": 1, + "clipOut": 1, + "handleStart": 0, + "handleEnd": 0, + "resolutionWidth": 1920, + "resolutionHeight": 1080, + "pixelAspect": 1, + "applications": [] +} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/global.json b/pype/settings/defaults/project_settings/global.json index 407dd23593..7cedd7cf88 100644 --- a/pype/settings/defaults/project_settings/global.json +++ b/pype/settings/defaults/project_settings/global.json @@ -161,24 +161,6 @@ } } }, - "attributes": { - "fps": 25, - "frameStart": 1001, - "frameEnd": 1001, - "clipIn": 1, - "clipOut": 1, - "handleStart": 0, - "handleEnd": 0, - "resolutionWidth": 1920, - "resolutionHeight": 1008, - "pixelAspect": 1, - "applications": [ - "maya_2020", - "nuke_12.2", - "hiero_12.2", - "blender_2.91" - ] - }, "project_folder_structure": { "__project_root__": { "prod": {}, diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json b/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json index 06937778d6..837eab0b43 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json @@ -14,7 +14,12 @@ "type": "anatomy_templates", "key": "templates", "is_file": true - }, { + }, + { + "type": "schema", + "name": "schema_anatomy_attributes" + }, + { "type": "schema", "name": "schema_anatomy_imageio" } diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_global.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_global.json index d78d430e9b..75731fe207 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_global.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_global.json @@ -13,10 +13,7 @@ "type": "schema", "name": "schema_global_tools" }, - { - "type": "schema", - "name": "schema_anatomy_attributes" - }, + { "type": "collapsible-wrap", "label": "Project Folder Structure", diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_anatomy_attributes.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_anatomy_attributes.json index c56e4432e3..6283100fca 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_anatomy_attributes.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_anatomy_attributes.json @@ -2,7 +2,7 @@ "type": "dict", "collapsable": true, "key": "attributes", - "label": "Project Attribute Defaults", + "label": "Attribute Defaults", "is_file": true, "children": [ { From 2960e994f213d2ef061a260889175b942189167d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Dec 2020 21:08:50 +0100 Subject: [PATCH 194/279] fix argument --- pype/tools/settings/settings/widgets/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index c1ff640837..9e8e6537f1 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -357,7 +357,7 @@ class SystemWidget(SettingsCategoryWidget): self.environ_fields.clear() super(SystemWidget, self).reset() - def save(self, all_values): + def save(self): _data = {} for input_field in self.input_fields: value, _is_group = input_field.studio_overrides() From 0de8a1ddb3e05480465c4dff5dfd5fcb36636e8a Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Wed, 2 Dec 2020 21:18:02 +0100 Subject: [PATCH 195/279] remove old default --- .../defaults/project_settings/attributes.json | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 pype/settings/defaults/project_settings/attributes.json diff --git a/pype/settings/defaults/project_settings/attributes.json b/pype/settings/defaults/project_settings/attributes.json deleted file mode 100644 index df586c105a..0000000000 --- a/pype/settings/defaults/project_settings/attributes.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "fps": 25, - "frameStart": 1001, - "frameEnd": 1001, - "clipIn": 1, - "clipOut": 1, - "handleStart": 0, - "handleEnd": 0, - "resolutionWidth": 1920, - "resolutionHeight": 1080, - "pixelAspect": 1, - "applications": [ - "maya_2019", - "nuke_12.2" - ] -} \ No newline at end of file From 722238d28329c7cef7ec850729afa0532351646a Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Wed, 2 Dec 2020 22:01:37 +0100 Subject: [PATCH 196/279] add ftrack custom attributes --- .../defaults/system_settings/modules.json | 66 ++++++ .../module_settings/schema_ftrack.json | 212 ++++++++++++------ 2 files changed, 209 insertions(+), 69 deletions(-) diff --git a/pype/settings/defaults/system_settings/modules.json b/pype/settings/defaults/system_settings/modules.json index cf2372dece..15b48a636e 100644 --- a/pype/settings/defaults/system_settings/modules.json +++ b/pype/settings/defaults/system_settings/modules.json @@ -36,6 +36,72 @@ }, "default": "-" }, + "custom_attributes": { + "show": { + "avalon_auto_sync": { + "default": "", + "write_security_role": [], + "read_security_role": [] + }, + "library_project": { + "default": "", + "write_security_role": [], + "read_security_role": [] + } + }, + "is_hierarchical": { + "fps": { + "default": "25", + "write_security_role": [], + "read_security_role": [] + }, + "frameStart": { + "default": "", + "write_security_role": [], + "read_security_role": [] + }, + "frameEnd": { + "default": "", + "write_security_role": [], + "read_security_role": [] + }, + "clipIn": { + "default": "", + "write_security_role": [], + "read_security_role": [] + }, + "clipOut": { + "default": "", + "write_security_role": [], + "read_security_role": [] + }, + "handleStart": { + "default": "", + "write_security_role": [], + "read_security_role": [] + }, + "handleEnd": { + "default": "", + "write_security_role": [], + "read_security_role": [] + }, + "resolutionWidth": { + "default": "", + "write_security_role": [], + "read_security_role": [] + }, + "resolutionHeight": { + "default": "", + "write_security_role": [], + "read_security_role": [] + }, + "pixelAspect": { + "default": "", + "write_security_role": [], + "read_security_role": [] + } + } + }, "environment": { "__environment_keys__": { "ftrack": [ diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json b/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json index 92fddc6298..fa4cd3eea8 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json @@ -4,86 +4,160 @@ "label": "Ftrack", "collapsable": true, "checkbox_key": "enabled", - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "text", + "key": "ftrack_server", + "label": "Server" + }, + { + "type": "splitter" + }, + { + "type": "label", + "label": "Additional Ftrack paths" + }, + { + "type": "list", + "key": "ftrack_actions_path", + "label": "Action paths", + "object_type": "text" + }, + { + "type": "list", + "key": "ftrack_events_path", + "label": "Event paths", + "object_type": "text" + }, + { + "type": "splitter" + }, + { + "type": "label", + "label": "Ftrack event server advanced settings" + }, + { + "type": "text", + "key": "FTRACK_EVENTS_MONGO_DB", + "label": "Event Mongo DB" + }, + { + "type": "text", + "key": "FTRACK_EVENTS_MONGO_COL", + "label": "Events Mongo Collection" + }, + { + "type": "splitter" + }, + { + "key": "intent", + "type": "dict", + "label": "Intent", + "collapsable_key": true, + "children": [ + { + "type": "label", + "label": "Intent" }, { - "type": "text", - "key": "ftrack_server", - "label": "Server" - }, - { - "type": "splitter" + "type": "dict-modifiable", + "object_type": "text", + "key": "items" }, { "type": "label", - "label": "Additional Ftrack paths" - }, - { - "type": "list", - "key": "ftrack_actions_path", - "label": "Action paths", - "object_type": "text" - }, - { - "type": "list", - "key": "ftrack_events_path", - "label": "Event paths", - "object_type": "text" - }, - { - "type": "splitter" - }, - { - "type": "label", - "label": "Ftrack event server advanced settings" + "label": " " }, { + "key": "default", "type": "text", - "key": "FTRACK_EVENTS_MONGO_DB", - "label": "Event Mongo DB" - }, + "label": "Default Intent" + }] + }, + { + "key": "custom_attributes", + "label": "Custom Attributes", + "type": "dict", + "children": [ { - "type": "text", - "key": "FTRACK_EVENTS_MONGO_COL", - "label": "Events Mongo Collection" - }, - { - "type": "splitter" - }, - { - "key": "intent", - "type": "dict", - "children": [{ - "type": "label", - "label": "Intent" - }, - { - "type": "dict-modifiable", - "object_type": "text", - "key": "items" - }, - { - "type": "label", - "label": " " - }, + "type": "dict-modifiable", + "label": "Show Attributes", + "key": "show", + "object_type": + { + "type": "dict", + "children": [ { "key": "default", - "type": "text", - "label": "Default Intent" - } - ] + "label": "default", + "type": "text" + }, + { + "key": "write_security_role", + "label": "write", + "type": "list", + "object_type": + { + "type": "text" + } + }, + { + "key": "read_security_role", + "label": "Read", + "type": "list", + "object_type": + { + "type": "text" + } + }] + } }, { - "type": "splitter" - }, - { - "key": "environment", - "label": "Environment", - "type": "raw-json", - "env_group_key": "ftrack" - } - ] + "type": "dict-modifiable", + "label": "Hierarchical Attributes", + "key": "is_hierarchical", + "object_type": + { + "type": "dict", + "children": [ + { + "key": "default", + "label": "default", + "type": "text" + }, + { + "key": "write_security_role", + "label": "write", + "type": "list", + "object_type": + { + "type": "text" + } + }, + { + "key": "read_security_role", + "label": "Read", + "type": "list", + "object_type": + { + "type": "text" + } + }] + } + }] + }, + { + "type": "splitter" + }, + { + "key": "environment", + "label": "Environment", + "type": "raw-json", + "env_group_key": "ftrack" + }] } From edc9cc3af19f5b204379ddd9f5a8e5557b62d28a Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Wed, 2 Dec 2020 22:02:56 +0100 Subject: [PATCH 197/279] remove old ftrack attributes --- .../ftrack/ftrack_custom_attributes.json | 66 ------------------- 1 file changed, 66 deletions(-) delete mode 100644 pype/settings/defaults/project_settings/ftrack/ftrack_custom_attributes.json diff --git a/pype/settings/defaults/project_settings/ftrack/ftrack_custom_attributes.json b/pype/settings/defaults/project_settings/ftrack/ftrack_custom_attributes.json deleted file mode 100644 index c4e204f716..0000000000 --- a/pype/settings/defaults/project_settings/ftrack/ftrack_custom_attributes.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "show": { - "avalon_auto_sync": { - "default": null, - "write_security_role": [], - "read_security_role": [] - }, - "library_project": { - "default": null, - "write_security_role": [], - "read_security_role": [] - } - }, - "is_hierarchical": { - "fps": { - "default": null, - "write_security_role": [], - "read_security_role": [] - }, - "clipIn": { - "default": null, - "write_security_role": [], - "read_security_role": [] - }, - "clipOut": { - "default": null, - "write_security_role": [], - "read_security_role": [] - }, - "frameStart": { - "default": null, - "write_security_role": [], - "read_security_role": [] - }, - "frameEnd": { - "default": null, - "write_security_role": [], - "read_security_role": [] - }, - "resolutionWidth": { - "default": null, - "write_security_role": [], - "read_security_role": [] - }, - "resolutionHeight": { - "default": null, - "write_security_role": [], - "read_security_role": [] - }, - "pixelAspect": { - "default": null, - "write_security_role": [], - "read_security_role": [] - }, - "handleStart": { - "default": null, - "write_security_role": [], - "read_security_role": [] - }, - "handleEnd": { - "default": null, - "write_security_role": [], - "read_security_role": [] - } - } -} From 81c4f21e1d9362ceab808a177be31c1a72a200cc Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Wed, 2 Dec 2020 22:14:54 +0100 Subject: [PATCH 198/279] add nuke 12.2 --- .../system_settings/applications.json | 104 ++++++++++++++++++ .../defaults/system_settings/modules.json | 22 +++- .../host_settings/template_nuke.json | 5 + 3 files changed, 129 insertions(+), 2 deletions(-) diff --git a/pype/settings/defaults/system_settings/applications.json b/pype/settings/defaults/system_settings/applications.json index 1393b94ff5..208a8dc5e5 100644 --- a/pype/settings/defaults/system_settings/applications.json +++ b/pype/settings/defaults/system_settings/applications.json @@ -250,6 +250,32 @@ } }, "variants": { + "nuke_12.2": { + "enabled": true, + "label": "", + "variant_label": "12.2", + "icon": "", + "executables": { + "windows": [ + [ + "C:\\Program Files\\Nuke12.2v3\\Nuke12.2.exe", + "" + ] + ], + "darwin": [], + "linux": [ + [ + "/usr/local/Nuke12.2v3Nuke12.2", + "" + ] + ] + }, + "environment": { + "__environment_keys__": { + "nuke_12.2": [] + } + } + }, "nuke_12.0": { "enabled": true, "label": "", @@ -347,6 +373,32 @@ } }, "variants": { + "nukex_12.2": { + "enabled": true, + "label": "", + "variant_label": "12.2", + "icon": "", + "executables": { + "windows": [ + [ + "C:\\Program Files\\Nuke12.2v3\\Nuke12.2.exe", + "--nukex" + ] + ], + "darwin": [], + "linux": [ + [ + "/usr/local/Nuke12.2v3Nuke12.2", + "--nukex" + ] + ] + }, + "environment": { + "__environment_keys__": { + "nukex_12.2": [] + } + } + }, "nukex_12.0": { "enabled": true, "label": "", @@ -448,6 +500,32 @@ "PYPE_LOG_NO_COLORS": "True" }, "variants": { + "nukestudio_12.2": { + "enabled": true, + "label": "", + "variant_label": "12.2", + "icon": "", + "executables": { + "windows": [ + [ + "C:\\Program Files\\Nuke12.2v3\\Nuke12.2.exe", + "--studio" + ] + ], + "darwin": [], + "linux": [ + [ + "/usr/local/Nuke12.2v3Nuke12.2", + "--studio" + ] + ] + }, + "environment": { + "__environment_keys__": { + "nukestudio_12.2": [] + } + } + }, "nukestudio_12.0": { "enabled": true, "label": "", @@ -544,6 +622,32 @@ "PYPE_LOG_NO_COLORS": "True" }, "variants": { + "hiero_12.2": { + "enabled": true, + "label": "", + "variant_label": "12.2", + "icon": "", + "executables": { + "windows": [ + [ + "C:\\Program Files\\Nuke12.2v3\\Nuke12.2.exe", + "--hiero" + ] + ], + "darwin": [], + "linux": [ + [ + "/usr/local/Nuke12.2v3Nuke12.2", + "--hiero" + ] + ] + }, + "environment": { + "__environment_keys__": { + "hiero_12.2": [] + } + } + }, "hiero_12.0": { "enabled": true, "label": "", diff --git a/pype/settings/defaults/system_settings/modules.json b/pype/settings/defaults/system_settings/modules.json index 15b48a636e..8c228e91ef 100644 --- a/pype/settings/defaults/system_settings/modules.json +++ b/pype/settings/defaults/system_settings/modules.json @@ -8,16 +8,34 @@ "avalon": [ "AVALON_CONFIG", "AVALON_PROJECTS", + "AVALON_USERNAME", + "AVALON_PASSWORD", + "AVALON_DEBUG", + "AVALON_MONGO", + "AVALON_DB", + "AVALON_DB_DATA", + "AVALON_EARLY_ADOPTER", "AVALON_SCHEMA", + "AVALON_LOCATION", "AVALON_LABEL", - "AVALON_TIMEOUT" + "AVALON_TIMEOUT", + "AVALON_THUMBNAIL_ROOT" ] }, "AVALON_CONFIG": "pype", "AVALON_PROJECTS": "{PYPE_PROJECTS_PATH}", + "AVALON_USERNAME": "avalon", + "AVALON_PASSWORD": "secret", + "AVALON_DEBUG": "1", + "AVALON_MONGO": "mongodb://localhost:2707", + "AVALON_DB": "avalon", + "AVALON_DB_DATA": "{PYPE_SETUP_PATH}/../mongo_db_data", + "AVALON_EARLY_ADOPTER": "1", "AVALON_SCHEMA": "{PYPE_MODULE_ROOT}/schema", + "AVALON_LOCATION": "http://127.0.0.1", "AVALON_LABEL": "Pype", - "AVALON_TIMEOUT": "1000" + "AVALON_TIMEOUT": "1000", + "AVALON_THUMBNAIL_ROOT": "{PYPE_SETUP_PATH}/../avalon_thumails" } }, "Ftrack": { diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/template_nuke.json b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/template_nuke.json index d335891b70..c00f8ae266 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/template_nuke.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/host_settings/template_nuke.json @@ -26,6 +26,11 @@ "type": "schema_template", "name": "template_host_variant", "template_data": [ + { + "host_version": "12.2", + "host_name": "{nuke_type}", + "multipath_executables": true + }, { "host_version": "12.0", "host_name": "{nuke_type}", From a03de3951a7dc0ec13d494057c0b1560f9a85d13 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Wed, 2 Dec 2020 22:22:11 +0100 Subject: [PATCH 199/279] remove obsolete settings --- .../defaults/system_settings/hosts.json | 34 ------------------- .../defaults/system_settings/intent.json | 8 ----- 2 files changed, 42 deletions(-) delete mode 100644 pype/settings/defaults/system_settings/hosts.json delete mode 100644 pype/settings/defaults/system_settings/intent.json diff --git a/pype/settings/defaults/system_settings/hosts.json b/pype/settings/defaults/system_settings/hosts.json deleted file mode 100644 index 35ee708df3..0000000000 --- a/pype/settings/defaults/system_settings/hosts.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "blender_2.80": true, - "blender_2.81": true, - "blender_2.82": true, - "blender_2.83": true, - "celaction_local": true, - "celaction_remote": true, - "harmony_17": true, - "maya_2017": true, - "maya_2018": true, - "maya_2019": true, - "maya_2020": true, - "nuke_10.0": true, - "nuke_11.2": true, - "nuke_11.3": true, - "nuke_12.0": true, - "nukex_10.0": true, - "nukex_11.2": true, - "nukex_11.3": true, - "nukex_12.0": true, - "nukestudio_10.0": true, - "nukestudio_11.2": true, - "nukestudio_11.3": true, - "nukestudio_12.0": true, - "houdini_16": true, - "houdini_16.5": true, - "houdini_17": true, - "houdini_18": true, - "premiere_2019": true, - "premiere_2020": true, - "resolve_16": true, - "storyboardpro_7": true, - "unreal_4.24": true -} \ No newline at end of file diff --git a/pype/settings/defaults/system_settings/intent.json b/pype/settings/defaults/system_settings/intent.json deleted file mode 100644 index 844bd1b518..0000000000 --- a/pype/settings/defaults/system_settings/intent.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "items": { - "wip": "WIP", - "test": "TEST", - "final": "FINAL" - }, - "default": "wip" -} \ No newline at end of file From 28d3cfe7f0ffe366b5f69ee35e2ab981ed2157bd Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Wed, 2 Dec 2020 23:21:47 +0100 Subject: [PATCH 200/279] convert anatomy to settings --- .../defaults/project_anatomy/templates.json | 7 +- .../projects_schema/schema_main.json | 8 +- .../schemas/schema_anatomy_attributes.json | 2 +- .../schemas/schema_anatomy_templates.json | 136 ++++++++++++++++++ 4 files changed, 144 insertions(+), 9 deletions(-) create mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_anatomy_templates.json diff --git a/pype/settings/defaults/project_anatomy/templates.json b/pype/settings/defaults/project_anatomy/templates.json index 0fff0265b3..32f962556f 100644 --- a/pype/settings/defaults/project_anatomy/templates.json +++ b/pype/settings/defaults/project_anatomy/templates.json @@ -13,9 +13,6 @@ "file": "{project[code]}_{asset}_{subset}_{@version}<_{output}><.{@frame}>.{representation}", "path": "{@folder}/{@file}" }, - "texture": { - "path": "{root}/{project[name]}/{hierarchy}/{asset}/publish/{family}/{subset}" - }, "publish": { "folder": "{root}/{project[name]}/{hierarchy}/{asset}/publish/{family}/{subset}/{@version}", "file": "{project[code]}_{asset}_{subset}_{@version}<_{output}><.{@frame}>.{representation}", @@ -26,5 +23,7 @@ "folder": "{root}/{project[name]}/{hierarchy}/{asset}/publish/{family}/{subset}/master", "file": "{project[code]}_{asset}_{subset}_master<_{output}><.{frame}>.{representation}", "path": "{@folder}/{@file}" - } + }, + "delivery": {}, + "other": {} } \ No newline at end of file diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_main.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_main.json index 837eab0b43..f0226446ea 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_main.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_main.json @@ -10,10 +10,10 @@ "type": "anatomy_roots", "key": "roots", "is_file": true - }, { - "type": "anatomy_templates", - "key": "templates", - "is_file": true + }, + { + "type": "schema", + "name": "schema_anatomy_templates" }, { "type": "schema", diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_anatomy_attributes.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_anatomy_attributes.json index 6283100fca..1ede46903c 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_anatomy_attributes.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_anatomy_attributes.json @@ -2,7 +2,7 @@ "type": "dict", "collapsable": true, "key": "attributes", - "label": "Attribute Defaults", + "label": "Attributes", "is_file": true, "children": [ { diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_anatomy_templates.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_anatomy_templates.json new file mode 100644 index 0000000000..2649178bff --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_anatomy_templates.json @@ -0,0 +1,136 @@ +{ + "type": "dict", + "collapsable": true, + "key": "templates", + "label": "Templates", + "collapsable_key": true, + "is_file": true, + "children": [ + { + "type": "number", + "key": "version_padding", + "label": "Version Padding" + }, + { + "type": "text", + "key": "version", + "label": "Version" + }, + { + "type": "number", + "key": "frame_padding", + "label": "Frame Padding" + }, + { + "type": "text", + "key": "frame", + "label": "Frame" + }, + { + "type": "dict", + "key": "work", + "label": "Work", + "children": [ + { + "type": "text", + "key": "folder", + "label": "Folder" + }, + { + "type": "text", + "key": "file", + "label": "File" + }, + { + "type": "text", + "key": "path", + "label": "Path" + }] + }, + { + "type": "dict", + "key": "render", + "label": "Render", + "children": [ + { + "type": "text", + "key": "folder", + "label": "Folder" + }, + { + "type": "text", + "key": "file", + "label": "File" + }, + { + "type": "text", + "key": "path", + "label": "Path" + } + + ] + }, + { + "type": "dict", + "key": "publish", + "label": "Publish", + "children": [ + { + "type": "text", + "key": "folder", + "label": "Folder" + }, + { + "type": "text", + "key": "file", + "label": "File" + }, + { + "type": "text", + "key": "path", + "label": "Path" + }, + { + "type": "text", + "key": "thumbnail", + "label": "Thumbnail" + }] + }, + { + "type": "dict", + "key": "master", + "label": "Master", + "children": [ + { + "type": "text", + "key": "folder", + "label": "Folder" + }, + { + "type": "text", + "key": "file", + "label": "File" + }, + { + "type": "text", + "key": "path", + "label": "Path" + } + + ] + }, + { + "type": "dict-modifiable", + "key": "delivery", + "label": "Delivery", + "object_type": "text" + }, + { + "type": "dict-modifiable", + "key": "other", + "label": "Other", + "object_type": "text" + } + + ] +} From 80a614261f8837e2208423a320722450523971af Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Wed, 2 Dec 2020 23:39:59 +0100 Subject: [PATCH 201/279] maya loade colors --- .../defaults/project_settings/maya.json | 91 ++++--------------- 1 file changed, 18 insertions(+), 73 deletions(-) diff --git a/pype/settings/defaults/project_settings/maya.json b/pype/settings/defaults/project_settings/maya.json index afc4442d0f..0c640a63e4 100644 --- a/pype/settings/defaults/project_settings/maya.json +++ b/pype/settings/defaults/project_settings/maya.json @@ -145,78 +145,23 @@ } }, "load": { - "colors": { - "model": [ - 0.0, - 0.0, - 0.0 - ], - "rig": [ - 0.0, - 0.0, - 0.0 - ], - "pointcache": [ - 0.0, - 0.0, - 0.0 - ], - "animation": [ - 0.0, - 0.0, - 0.0 - ], - "ass": [ - 0.0, - 0.0, - 0.0 - ], - "camera": [ - 0.0, - 0.0, - 0.0 - ], - "fbx": [ - 0.0, - 0.0, - 0.0 - ], - "mayaAscii": [ - 0.0, - 0.0, - 0.0 - ], - "setdress": [ - 0.0, - 0.0, - 0.0 - ], - "layout": [ - 0.0, - 0.0, - 0.0 - ], - "vdbcache": [ - 0.0, - 0.0, - 0.0 - ], - "vrayproxy": [ - 0.0, - 0.0, - 0.0 - ], - "yeticache": [ - 0.0, - 0.0, - 0.0 - ], - "yetiRig": [ - 0.0, - 0.0, - 0.0 - ] - } + "colors": { + "model": [0.821, 0.518, 0.117], + "rig": [0.144, 0.443, 0.463], + "pointcache": [0.368, 0.821, 0.117], + "animation": [0.368, 0.821, 0.117], + "ass": [1.0, 0.332, 0.312], + "camera": [0.447, 0.312, 1.0], + "camerarig": [0.447, 0.312, 1.0], + "fbx": [1.0, 0.931, 0.312], + "mayaAscii": [0.312, 1.0, 0.747], + "setdress": [0.312, 1.0, 0.747], + "layout": [0.312, 1.0, 0.747], + "vdbcache": [0.312, 1.0, 0.428], + "vrayproxy": [0.258, 0.95, 0.541], + "yeticache": [0.2, 0.8, 0.3], + "yetiRig": [0, 0.8, 0.5] + } }, "workfile_build": { "profiles": [ @@ -316,4 +261,4 @@ "ValidateNoAnimation": false } } -} \ No newline at end of file +} From d5473aee74c1e816a2ae2f381cd1e59dab0b132e Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 00:02:43 +0100 Subject: [PATCH 202/279] refactor maya loaders config to settings --- pype/plugins/maya/load/load_ass.py | 10 +++++----- pype/plugins/maya/load/load_gpucache.py | 6 +++--- pype/plugins/maya/load/load_reference.py | 6 +++--- pype/plugins/maya/load/load_vdb_to_redshift.py | 6 +++--- pype/plugins/maya/load/load_vdb_to_vray.py | 6 +++--- pype/plugins/maya/load/load_vrayproxy.py | 6 +++--- pype/plugins/maya/load/load_yeti_cache.py | 6 +++--- pype/plugins/maya/load/load_yeti_rig.py | 6 +++--- 8 files changed, 26 insertions(+), 26 deletions(-) diff --git a/pype/plugins/maya/load/load_ass.py b/pype/plugins/maya/load/load_ass.py index ffe70c39e8..dc3e0043ee 100644 --- a/pype/plugins/maya/load/load_ass.py +++ b/pype/plugins/maya/load/load_ass.py @@ -1,7 +1,7 @@ from avalon import api import pype.hosts.maya.plugin import os -from pype.api import config +from pype.api import project_settings import clique @@ -74,8 +74,8 @@ class AssProxyLoader(pype.hosts.maya.plugin.ReferenceLoader): proxyShape.dso.set(path) proxyShape.aiOverrideShaders.set(0) - presets = config.get_presets(project=os.environ['AVALON_PROJECT']) - colors = presets['plugins']['maya']['load']['colors'] + settings = project_settings(os.environ['AVALON_PROJECT']) + colors = settings['maya']['load']['colors'] c = colors.get(family) if c is not None: @@ -196,8 +196,8 @@ class AssStandinLoader(api.Loader): label = "{}:{}".format(namespace, name) root = pm.group(name=label, empty=True) - presets = config.get_presets(project=os.environ['AVALON_PROJECT']) - colors = presets['plugins']['maya']['load']['colors'] + settings = project_settings(os.environ['AVALON_PROJECT']) + colors = settings['maya']['load']['colors'] c = colors.get('ass') if c is not None: diff --git a/pype/plugins/maya/load/load_gpucache.py b/pype/plugins/maya/load/load_gpucache.py index 9930dbaac6..6520be0a07 100644 --- a/pype/plugins/maya/load/load_gpucache.py +++ b/pype/plugins/maya/load/load_gpucache.py @@ -1,7 +1,7 @@ from avalon import api import pype.hosts.maya.plugin import os -from pype.api import config +from pype.api import project_settings reload(config) @@ -35,8 +35,8 @@ class GpuCacheLoader(api.Loader): label = "{}:{}".format(namespace, name) root = cmds.group(name=label, empty=True) - presets = config.get_presets(project=os.environ['AVALON_PROJECT']) - colors = presets['plugins']['maya']['load']['colors'] + settings = project_settings(os.environ['AVALON_PROJECT']) + colors = settings['maya']['load']['colors'] c = colors.get('model') if c is not None: cmds.setAttr(root + ".useOutlinerColor", 1) diff --git a/pype/plugins/maya/load/load_reference.py b/pype/plugins/maya/load/load_reference.py index dbb3cc98b2..90a3015894 100644 --- a/pype/plugins/maya/load/load_reference.py +++ b/pype/plugins/maya/load/load_reference.py @@ -2,7 +2,7 @@ import pype.hosts.maya.plugin from avalon import api, maya from maya import cmds import os -from pype.api import config +from pype.api import project_settings class ReferenceLoader(pype.hosts.maya.plugin.ReferenceLoader): @@ -77,8 +77,8 @@ class ReferenceLoader(pype.hosts.maya.plugin.ReferenceLoader): cmds.setAttr(groupName + ".displayHandle", 1) - presets = config.get_presets(project=os.environ['AVALON_PROJECT']) - colors = presets['plugins']['maya']['load']['colors'] + settings = project_settings(os.environ['AVALON_PROJECT']) + colors = settings['maya']['load']['colors'] c = colors.get(family) if c is not None: groupNode.useOutlinerColor.set(1) diff --git a/pype/plugins/maya/load/load_vdb_to_redshift.py b/pype/plugins/maya/load/load_vdb_to_redshift.py index 4893640b27..885f0f23c8 100644 --- a/pype/plugins/maya/load/load_vdb_to_redshift.py +++ b/pype/plugins/maya/load/load_vdb_to_redshift.py @@ -1,6 +1,6 @@ from avalon import api import os -from pype.api import config +from pype.api import project_settings class LoadVDBtoRedShift(api.Loader): """Load OpenVDB in a Redshift Volume Shape""" @@ -55,8 +55,8 @@ class LoadVDBtoRedShift(api.Loader): label = "{}:{}".format(namespace, name) root = cmds.group(name=label, empty=True) - presets = config.get_presets(project=os.environ['AVALON_PROJECT']) - colors = presets['plugins']['maya']['load']['colors'] + settings = project_settings(os.environ['AVALON_PROJECT']) + colors = settings['maya']['load']['colors'] c = colors.get(family) if c is not None: diff --git a/pype/plugins/maya/load/load_vdb_to_vray.py b/pype/plugins/maya/load/load_vdb_to_vray.py index aee0ee026d..9bfdda0308 100644 --- a/pype/plugins/maya/load/load_vdb_to_vray.py +++ b/pype/plugins/maya/load/load_vdb_to_vray.py @@ -1,5 +1,5 @@ from avalon import api -from pype.api import config +from pype.api import project_settings import os @@ -48,8 +48,8 @@ class LoadVDBtoVRay(api.Loader): label = "{}:{}".format(namespace, name) root = cmds.group(name=label, empty=True) - presets = config.get_presets(project=os.environ['AVALON_PROJECT']) - colors = presets['plugins']['maya']['load']['colors'] + settings = project_settings(os.environ['AVALON_PROJECT']) + colors = settings['maya']['load']['colors'] c = colors.get(family) if c is not None: diff --git a/pype/plugins/maya/load/load_vrayproxy.py b/pype/plugins/maya/load/load_vrayproxy.py index 894ec75c32..1294df2fc7 100644 --- a/pype/plugins/maya/load/load_vrayproxy.py +++ b/pype/plugins/maya/load/load_vrayproxy.py @@ -1,6 +1,6 @@ from avalon.maya import lib from avalon import api -from pype.api import config +from pype.api import project_settings import os import maya.cmds as cmds @@ -47,8 +47,8 @@ class VRayProxyLoader(api.Loader): return # colour the group node - presets = config.get_presets(project=os.environ['AVALON_PROJECT']) - colors = presets['plugins']['maya']['load']['colors'] + settings = project_settings(os.environ['AVALON_PROJECT']) + colors = settings['maya']['load']['colors'] c = colors.get(family) if c is not None: cmds.setAttr("{0}.useOutlinerColor".format(group_node), 1) diff --git a/pype/plugins/maya/load/load_yeti_cache.py b/pype/plugins/maya/load/load_yeti_cache.py index ef0b5d5efa..8ee1602202 100644 --- a/pype/plugins/maya/load/load_yeti_cache.py +++ b/pype/plugins/maya/load/load_yeti_cache.py @@ -9,7 +9,7 @@ from maya import cmds from avalon import api, io from avalon.maya import lib as avalon_lib, pipeline from pype.hosts.maya import lib -from pype.api import config +from pype.api import project_settings from pprint import pprint @@ -59,8 +59,8 @@ class YetiCacheLoader(api.Loader): group_name = "{}:{}".format(namespace, name) group_node = cmds.group(nodes, name=group_name) - presets = config.get_presets(project=os.environ['AVALON_PROJECT']) - colors = presets['plugins']['maya']['load']['colors'] + settings = project_settings(os.environ['AVALON_PROJECT']) + colors = settings['maya']['load']['colors'] c = colors.get(family) if c is not None: diff --git a/pype/plugins/maya/load/load_yeti_rig.py b/pype/plugins/maya/load/load_yeti_rig.py index 0604953198..bd74fcbc43 100644 --- a/pype/plugins/maya/load/load_yeti_rig.py +++ b/pype/plugins/maya/load/load_yeti_rig.py @@ -1,7 +1,7 @@ import os from collections import defaultdict -from pype.api import config +from pype.api import project_settings import pype.hosts.maya.plugin from pype.hosts.maya import lib @@ -77,8 +77,8 @@ class YetiRigLoader(pype.hosts.maya.plugin.ReferenceLoader): groupName = "{}:{}".format(namespace, name) - presets = config.get_presets(project=os.environ['AVALON_PROJECT']) - colors = presets['plugins']['maya']['load']['colors'] + settings = project_settings(os.environ['AVALON_PROJECT']) + colors = settings['maya']['load']['colors'] c = colors.get('yetiRig') if c is not None: From 8798bec8f0c2dda76cb33687ef092a4914fd31fd Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 00:03:11 +0100 Subject: [PATCH 203/279] refactor maya muster submit config to settings --- pype/plugins/maya/publish/submit_maya_muster.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pype/plugins/maya/publish/submit_maya_muster.py b/pype/plugins/maya/publish/submit_maya_muster.py index ffe434048a..df75fce1a4 100644 --- a/pype/plugins/maya/publish/submit_maya_muster.py +++ b/pype/plugins/maya/publish/submit_maya_muster.py @@ -11,7 +11,7 @@ from avalon.vendor import requests import pyblish.api from pype.hosts.maya import lib -from pype.api import config +from pype.api import system_settings # mapping between Maya renderer names and Muster template ids @@ -25,10 +25,9 @@ def _get_template_id(renderer): :rtype: int """ - templates = config.get_presets()["muster"]["templates_mapping"] + templates = system_settings()["modules"]["Muster"]["templates_mapping"] if not templates: - raise RuntimeError(("Muster template mapping missing in pype-config " - "`presets/muster/templates_mapping.json`")) + raise RuntimeError(("Muster template mapping missing in pype-settings")) try: template_id = templates[renderer] except KeyError: From ad6b4bf895058e6bb5645e5fd543dd28cb5dda9b Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 00:03:30 +0100 Subject: [PATCH 204/279] refactor rendersetup example to settings --- pype/plugins/maya/create/create_rendersetup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pype/plugins/maya/create/create_rendersetup.py b/pype/plugins/maya/create/create_rendersetup.py index 98f54f2d70..406d90223f 100644 --- a/pype/plugins/maya/create/create_rendersetup.py +++ b/pype/plugins/maya/create/create_rendersetup.py @@ -26,10 +26,10 @@ class CreateRenderSetup(avalon.maya.Creator): # \__| | # \_____/ - # from pype.api import config + # from pype.api import project_settings # import maya.app.renderSetup.model.renderSetup as renderSetup - # presets = config.get_presets(project=os.environ['AVALON_PROJECT']) - # layer = presets['plugins']['maya']['create']['renderSetup']["layer"] + # settings = project_settings(os.environ['AVALON_PROJECT']) + # layer = settings['maya']['create']['renderSetup']["layer"] # rs = renderSetup.instance() # rs.createRenderLayer(layer) From a97cc086edff55867ef8170bab02a7736cad7787 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 10:41:05 +0100 Subject: [PATCH 205/279] settings function names are with verbs now --- pype/api.py | 8 ++--- pype/lib/applications.py | 8 ++--- pype/modules_manager.py | 4 +-- pype/settings/__init__.py | 12 +++---- pype/settings/lib.py | 30 ++++++++-------- pype/tools/settings/settings/widgets/base.py | 36 ++++++++++---------- 6 files changed, 49 insertions(+), 49 deletions(-) diff --git a/pype/api.py b/pype/api.py index b88be4cc88..48a6cfcb92 100644 --- a/pype/api.py +++ b/pype/api.py @@ -1,6 +1,6 @@ from .settings import ( - system_settings, - project_settings, + get_system_settings, + get_project_settings, environments ) from pypeapp import ( @@ -50,8 +50,8 @@ from .lib import ( from .lib import _subprocess as subprocess __all__ = [ - "system_settings", - "project_settings", + "get_system_settings", + "get_project_settings", "environments", "Logger", diff --git a/pype/lib/applications.py b/pype/lib/applications.py index ddff9ddcd2..1a5b70f339 100644 --- a/pype/lib/applications.py +++ b/pype/lib/applications.py @@ -19,8 +19,8 @@ from ..api import ( Anatomy, Logger, config, - system_settings, - environments + get_system_settings, + get_environments ) from .python_module_tools import ( modules_from_path, @@ -526,7 +526,7 @@ class ApplicationManager: def refresh(self): """Refresh applications from settings.""" - settings = system_settings() + settings = get_system_settings() hosts_definitions = settings["applications"] for app_group, variant_definitions in hosts_definitions.items(): @@ -905,7 +905,7 @@ class ApplicationLaunchContext: # Load settings if were not passed in data settings_env = self.data.get("settings_env") if settings_env is None: - settings_env = environments() + settings_env = get_environments() self.data["settings_env"] = settings_env # subprocess.Popen launch arguments (first argument in constructor) diff --git a/pype/modules_manager.py b/pype/modules_manager.py index 6538187ea9..72023500e4 100644 --- a/pype/modules_manager.py +++ b/pype/modules_manager.py @@ -3,7 +3,7 @@ import inspect import pype.modules from pype.modules import PypeModule -from pype.settings import system_settings +from pype.settings import get_system_settings from pype.api import Logger @@ -24,7 +24,7 @@ class PypeModuleManager: return environments def find_pype_modules(self): - settings = system_settings() + settings = get_system_settings() modules = [] dirpath = os.path.dirname(pype.modules.__file__) for module_name in os.listdir(dirpath): diff --git a/pype/settings/__init__.py b/pype/settings/__init__.py index 7a99ba0b2f..d078815849 100644 --- a/pype/settings/__init__.py +++ b/pype/settings/__init__.py @@ -1,11 +1,11 @@ from .lib import ( - system_settings, - project_settings, - environments + get_system_settings, + get_project_settings, + get_environments ) __all__ = ( - "system_settings", - "project_settings", - "environments" + "get_system_settings", + "get_project_settings", + "get_environments" ) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index ebd0d86df4..0fd2595f3e 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -69,7 +69,7 @@ def reset_default_settings(): _DEFAULT_SETTINGS = None -def default_settings(): +def get_default_settings(): global _DEFAULT_SETTINGS if _DEFAULT_SETTINGS is None: _DEFAULT_SETTINGS = load_jsons_from_dir(DEFAULTS_DIR) @@ -236,21 +236,21 @@ def subkey_merge(_dict, value, keys): return _dict -def studio_system_settings(): +def get_studio_system_settings(): """Studio overrides of system settings.""" if os.path.exists(SYSTEM_SETTINGS_PATH): return load_json_file(SYSTEM_SETTINGS_PATH) return {} -def studio_project_settings(): +def get_studio_project_settings(): """Studio overrides of default project settings.""" if os.path.exists(PROJECT_SETTINGS_PATH): return load_json_file(PROJECT_SETTINGS_PATH) return {} -def studio_project_anatomy(): +def get_studio_project_anatomy(): """Studio overrides of default project anatomy data.""" if os.path.exists(PROJECT_ANATOMY_PATH): return load_json_file(PROJECT_ANATOMY_PATH) @@ -305,8 +305,8 @@ def save_project_settings(project_name, overrides): Do not use to store whole project settings data with defaults but only it's overrides with metadata defining how overrides should be applied in load - function. For loading should be used functions `studio_project_settings` - for global project settings and `project_settings_overrides` for + function. For loading should be used function `get_studio_project_settings` + for global project settings and `get_project_settings_overrides` for project specific settings. Args: @@ -346,7 +346,7 @@ def save_project_anatomy(project_name, anatomy_data): json.dump(anatomy_data, file_stream, indent=4) -def project_settings_overrides(project_name): +def get_project_settings_overrides(project_name): """Studio overrides of project settings for specific project. Args: @@ -412,26 +412,26 @@ def apply_overrides(source_data, override_data): return merge_overrides(_source_data, override_data) -def system_settings(): +def get_system_settings(): """System settings with applied studio overrides.""" - default_values = default_settings()[SYSTEM_SETTINGS_KEY] - studio_values = studio_system_settings() + default_values = get_default_settings()[SYSTEM_SETTINGS_KEY] + studio_values = get_studio_system_settings() return apply_overrides(default_values, studio_values) -def project_settings(project_name): +def get_project_settings(project_name): """Project settings with applied studio and project overrides.""" - default_values = default_settings()[PROJECT_SETTINGS_KEY] - studio_values = studio_project_settings() + default_values = get_default_settings()[PROJECT_SETTINGS_KEY] + studio_values = get_studio_project_settings() studio_overrides = apply_overrides(default_values, studio_values) - project_overrides = project_settings_overrides(project_name) + project_overrides = get_project_settings_overrides(project_name) return apply_overrides(studio_overrides, project_overrides) -def environments(): +def get_environments(): """Calculated environment based on defaults and system settings. Any default environment also found in the system settings will be fully diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index 9e8e6537f1..7a43952cfd 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -10,14 +10,14 @@ from pype.settings.lib import ( DEFAULTS_DIR, reset_default_settings, - default_settings, + get_default_settings, - studio_system_settings, - studio_project_settings, - studio_project_anatomy, + get_studio_system_settings, + get_studio_project_settings, + get_studio_project_anatomy, - project_settings_overrides, - project_anatomy_overrides, + get_project_settings_overrides, + get_project_anatomy_overrides, save_studio_settings, save_project_settings, @@ -322,7 +322,7 @@ class SystemWidget(SettingsCategoryWidget): def duplicated_env_group_validation(self, values=None, overrides=None): try: if overrides is not None: - default_values = default_settings()[SYSTEM_SETTINGS_KEY] + default_values = get_default_settings()[SYSTEM_SETTINGS_KEY] values = apply_overrides(default_values, overrides) else: values = copy.deepcopy(values) @@ -375,7 +375,7 @@ class SystemWidget(SettingsCategoryWidget): def update_values(self): default_values = lib.convert_data_to_gui_data({ - self.main_schema_key: default_settings()[SYSTEM_SETTINGS_KEY] + self.main_schema_key: get_default_settings()[SYSTEM_SETTINGS_KEY] }) for input_field in self.input_fields: input_field.update_default_values(default_values) @@ -384,7 +384,7 @@ class SystemWidget(SettingsCategoryWidget): system_values = lib.NOT_SET else: system_values = lib.convert_overrides_to_gui_data( - {self.main_schema_key: studio_system_settings()} + {self.main_schema_key: get_studio_system_settings()} ) for input_field in self.input_fields: @@ -549,8 +549,8 @@ class ProjectWidget(SettingsCategoryWidget): _project_anatomy = lib.NOT_SET self.is_overidable = False else: - _project_overrides = project_settings_overrides(project_name) - _project_anatomy = project_anatomy_overrides(project_name) + _project_overrides = get_project_settings_overrides(project_name) + _project_anatomy = get_project_anatomy_overrides(project_name) self.is_overidable = True overrides = {self.main_schema_key: { @@ -590,16 +590,16 @@ class ProjectWidget(SettingsCategoryWidget): project_anatomy_data = output_data.get(PROJECT_ANATOMY_KEY, {}) save_project_anatomy(self.project_name, project_anatomy_data) - if self.project_name: - # Refill values with overrides - self._on_project_change() - else: + if studio_overrides: # Update saved values self._update_values() + else: + # Refill values with overrides + self._on_project_change() def update_values(self): default_values = lib.convert_data_to_gui_data( - {self.main_schema_key: default_settings()} + {self.main_schema_key: get_default_settings()} ) for input_field in self.input_fields: input_field.update_default_values(default_values) @@ -609,8 +609,8 @@ class ProjectWidget(SettingsCategoryWidget): else: studio_values = lib.convert_overrides_to_gui_data({ self.main_schema_key: { - PROJECT_SETTINGS_KEY: studio_project_settings(), - PROJECT_ANATOMY_KEY: studio_project_anatomy() + PROJECT_SETTINGS_KEY: get_studio_project_settings(), + PROJECT_ANATOMY_KEY: get_studio_project_anatomy() } }) From 0685c98c77bf92882a408e9233ef9bce6bfa9bb1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 10:41:19 +0100 Subject: [PATCH 206/279] fixed json decode exception for python 2 --- pype/settings/lib.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index 0fd2595f3e..df4a19d7b4 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -5,6 +5,9 @@ import copy log = logging.getLogger(__name__) +# Py2 + Py3 json decode exception +JSON_EXC = getattr(json.decoder, "JSONDecodeError", ValueError) + # Metadata keys for work with studio and project overrides M_OVERRIDEN_KEY = "__overriden_keys__" # Metadata key for storing information about environments @@ -82,7 +85,7 @@ def load_json_file(fpath): with open(fpath, "r") as opened_file: return json.load(opened_file) - except json.decoder.JSONDecodeError: + except JSON_EXC: log.warning( "File has invalid json format \"{}\"".format(fpath), exc_info=True From 7db9a0ca9d9001d7528928f3ed23dde1a3bfc173 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 10:43:12 +0100 Subject: [PATCH 207/279] get_environments skip deprecated environemnts loading --- pype/settings/lib.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index df4a19d7b4..a66e14e28e 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -443,11 +443,5 @@ def get_environments(): Returns: dict: Output should be ready for `acre` module. """ - # TODO remove these defaults (All should be set with system settings) - envs = copy.deepcopy(default_settings()[ENVIRONMENTS_KEY]) - # This is part of loading environments from settings - envs_from_system_settings = find_environments(system_settings()) - for env_group_key, values in envs_from_system_settings.items(): - envs[env_group_key] = values - return envs + return find_environments(get_system_settings()) From 79b4cc9f115d266113505e44536b07fc87a69a90 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 10:43:44 +0100 Subject: [PATCH 208/279] added function `get_anatomy_data` to get anatomy data --- pype/settings/lib.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index a66e14e28e..9ca9872958 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -367,7 +367,7 @@ def get_project_settings_overrides(project_name): return load_json_file(path_to_json) -def project_anatomy_overrides(project_name): +def get_project_anatomy_overrides(project_name): """Studio overrides of project anatomy for specific project. Args: @@ -434,6 +434,18 @@ def get_project_settings(project_name): return apply_overrides(studio_overrides, project_overrides) +def get_anatomy_data(project_name): + """Project anatomy data with applied studio and project overrides.""" + default_values = get_default_settings()[PROJECT_ANATOMY_KEY] + studio_values = get_studio_project_anatomy() + + studio_overrides = apply_overrides(default_values, studio_values) + + project_overrides = get_project_anatomy_overrides(project_name) + + return apply_overrides(studio_overrides, project_overrides) + + def get_environments(): """Calculated environment based on defaults and system settings. From 2dadab864320b57bc1a7cc5447cf1ee6263047ae Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 11:00:09 +0100 Subject: [PATCH 209/279] fixed api imports --- pype/api.py | 6 ++++-- pype/settings/__init__.py | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pype/api.py b/pype/api.py index 48a6cfcb92..34e2c79845 100644 --- a/pype/api.py +++ b/pype/api.py @@ -1,7 +1,8 @@ from .settings import ( get_system_settings, get_project_settings, - environments + get_anatomy_data, + get_environments ) from pypeapp import ( Logger, @@ -52,7 +53,8 @@ from .lib import _subprocess as subprocess __all__ = [ "get_system_settings", "get_project_settings", - "environments", + "get_anatomy_data", + "get_environments", "Logger", "Anatomy", diff --git a/pype/settings/__init__.py b/pype/settings/__init__.py index d078815849..2f487038bd 100644 --- a/pype/settings/__init__.py +++ b/pype/settings/__init__.py @@ -1,11 +1,13 @@ from .lib import ( get_system_settings, get_project_settings, + get_anatomy_data, get_environments ) __all__ = ( "get_system_settings", "get_project_settings", + "get_anatomy_data", "get_environments" ) From f7655dbb442bf91967c9f596c0f5f30cf5ecaaea Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 11:09:57 +0100 Subject: [PATCH 210/279] change automatic plugin config loading to settings --- pype/__init__.py | 9 +++++---- pype/lib/plugin_tools.py | 6 +++--- pype/plugin.py | 8 +++++--- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/pype/__init__.py b/pype/__init__.py index 2a922547e8..928bff6e9d 100644 --- a/pype/__init__.py +++ b/pype/__init__.py @@ -2,7 +2,7 @@ import os from pyblish import api as pyblish from avalon import api as avalon -from .api import config, Anatomy +from .api import project_settings, Anatomy from .lib import filter_pyblish_plugins @@ -50,14 +50,14 @@ def patched_discover(superclass): print(">>> trying to find presets for {}:{} ...".format(host, plugin_type)) try: - config_data = config.get_presets()['plugins'][host][plugin_type] + settings = project_settings(os.environ['AVALON_PROJECT'])[host][plugin_type] except KeyError: print("*** no presets found.") else: for plugin in plugins: - if plugin.__name__ in config_data: + if plugin.__name__ in settings: print(">>> We have preset for {}".format(plugin.__name__)) - for option, value in config_data[plugin.__name__].items(): + for option, value in settings[plugin.__name__].items(): if option == "enabled" and value is False: setattr(plugin, "active", False) print(" - is disabled by preset") @@ -104,6 +104,7 @@ def install(): anatomy.set_root_environments() avalon.register_root(anatomy.roots) # apply monkey patched discover to original one + log.info("Patching discovery") avalon.discover = patched_discover diff --git a/pype/lib/plugin_tools.py b/pype/lib/plugin_tools.py index 0b6ace807e..185ebce10f 100644 --- a/pype/lib/plugin_tools.py +++ b/pype/lib/plugin_tools.py @@ -4,7 +4,7 @@ import os import inspect import logging -from ..api import config +from ..api import config, project_settings log = logging.getLogger(__name__) @@ -25,7 +25,7 @@ def filter_pyblish_plugins(plugins): host = api.current_host() - presets = config.get_presets().get('plugins', {}) + presets = project_settings(os.environ['AVALON_PROJECT']) or {} # iterate over plugins for plugin in plugins[:]: @@ -53,7 +53,7 @@ def filter_pyblish_plugins(plugins): log.info('removing plugin {}'.format(plugin.__name__)) plugins.remove(plugin) else: - log.info('setting {}:{} on plugin {}'.format( + log.info('setting XXX {}:{} on plugin {}'.format( option, value, plugin.__name__)) setattr(plugin, option, value) diff --git a/pype/plugin.py b/pype/plugin.py index a169e82beb..8d53e9c4be 100644 --- a/pype/plugin.py +++ b/pype/plugin.py @@ -2,7 +2,7 @@ import tempfile import os import pyblish.api -from pype.api import config +from pype.api import project_settings import inspect ValidatePipelineOrder = pyblish.api.ValidatorOrder + 0.05 @@ -24,12 +24,14 @@ def imprint_attributes(plugin): plugin_host = file.split(os.path.sep)[-3:-2][0] plugin_name = type(plugin).__name__ try: - config_data = config.get_presets()['plugins'][plugin_host][plugin_kind][plugin_name] # noqa: E501 + settings = project_settings(os.environ['AVALON_PROJECT']) + settings_data = settings[plugin_host][plugin_kind][plugin_name] # noqa: E501 + print(settings_data) except KeyError: print("preset not found") return - for option, value in config_data.items(): + for option, value in settings_data.items(): if option == "enabled" and value is False: setattr(plugin, "active", False) else: From 8e1f1fc7ccd97edfbe655cc168e1791100e11c93 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 11:19:13 +0100 Subject: [PATCH 211/279] make cleaner get overrides function names --- pype/settings/lib.py | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index 9ca9872958..0cdab1d7b5 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -239,27 +239,6 @@ def subkey_merge(_dict, value, keys): return _dict -def get_studio_system_settings(): - """Studio overrides of system settings.""" - if os.path.exists(SYSTEM_SETTINGS_PATH): - return load_json_file(SYSTEM_SETTINGS_PATH) - return {} - - -def get_studio_project_settings(): - """Studio overrides of default project settings.""" - if os.path.exists(PROJECT_SETTINGS_PATH): - return load_json_file(PROJECT_SETTINGS_PATH) - return {} - - -def get_studio_project_anatomy(): - """Studio overrides of default project anatomy data.""" - if os.path.exists(PROJECT_ANATOMY_PATH): - return load_json_file(PROJECT_ANATOMY_PATH) - return {} - - def path_to_project_settings(project_name): if not project_name: return PROJECT_SETTINGS_PATH @@ -349,6 +328,27 @@ def save_project_anatomy(project_name, anatomy_data): json.dump(anatomy_data, file_stream, indent=4) +def get_studio_overrides_system_settings(): + """Studio overrides of system settings.""" + if os.path.exists(SYSTEM_SETTINGS_PATH): + return load_json_file(SYSTEM_SETTINGS_PATH) + return {} + + +def get_studio_overrides_default_project_settings(): + """Studio overrides of default project settings.""" + if os.path.exists(PROJECT_SETTINGS_PATH): + return load_json_file(PROJECT_SETTINGS_PATH) + return {} + + +def get_studio_overrides_default_project_anatomy(): + """Studio overrides of default project anatomy data.""" + if os.path.exists(PROJECT_ANATOMY_PATH): + return load_json_file(PROJECT_ANATOMY_PATH) + return {} + + def get_project_settings_overrides(project_name): """Studio overrides of project settings for specific project. From 09a62d805012f443be29f52269a364f377fd81db Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 11:19:50 +0100 Subject: [PATCH 212/279] added get_default_project_anatomy_data and get_default_project_settings --- pype/settings/lib.py | 42 +++++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index 0cdab1d7b5..1b98ce19aa 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -418,34 +418,54 @@ def apply_overrides(source_data, override_data): def get_system_settings(): """System settings with applied studio overrides.""" default_values = get_default_settings()[SYSTEM_SETTINGS_KEY] - studio_values = get_studio_system_settings() + studio_values = get_studio_overrides_system_settings() return apply_overrides(default_values, studio_values) -def get_project_settings(project_name): - """Project settings with applied studio and project overrides.""" +def get_default_project_settings(): + """Project settings with applied studio's default project overrides.""" default_values = get_default_settings()[PROJECT_SETTINGS_KEY] - studio_values = get_studio_project_settings() + studio_values = get_studio_overrides_default_project_settings() - studio_overrides = apply_overrides(default_values, studio_values) + return apply_overrides(default_values, studio_values) - project_overrides = get_project_settings_overrides(project_name) - return apply_overrides(studio_overrides, project_overrides) +def get_default_project_anatomy_data(): + """Project anatomy data with applied studio's default project overrides.""" + default_values = get_default_settings()[PROJECT_ANATOMY_KEY] + studio_values = get_studio_overrides_default_project_anatomy() + + return apply_overrides(default_values, studio_values) def get_anatomy_data(project_name): """Project anatomy data with applied studio and project overrides.""" - default_values = get_default_settings()[PROJECT_ANATOMY_KEY] - studio_values = get_studio_project_anatomy() - - studio_overrides = apply_overrides(default_values, studio_values) + if not project_name: + raise ValueError( + "Must enter project name." + " Call `get_default_project_anatomy_data` to get project defaults." + ) + studio_overrides = get_default_project_anatomy_data() project_overrides = get_project_anatomy_overrides(project_name) return apply_overrides(studio_overrides, project_overrides) +def get_project_settings(project_name): + """Project settings with applied studio and project overrides.""" + if not project_name: + raise ValueError( + "Must enter project name." + " Call `get_default_project_settings` to get project defaults." + ) + + studio_overrides = get_default_project_settings() + project_overrides = get_project_settings_overrides(project_name) + + return apply_overrides(studio_overrides, project_overrides) + + def get_environments(): """Calculated environment based on defaults and system settings. From a5c5e7262c5ceeb94edba32ed3f5fd876e7aa60a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 11:20:05 +0100 Subject: [PATCH 213/279] setting gui use new overrides functions --- pype/tools/settings/settings/widgets/base.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index 7a43952cfd..ec86da74c4 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -12,9 +12,9 @@ from pype.settings.lib import ( reset_default_settings, get_default_settings, - get_studio_system_settings, - get_studio_project_settings, - get_studio_project_anatomy, + get_studio_overrides_system_settings, + get_studio_overrides_default_project_settings, + get_studio_overrides_default_project_anatomy, get_project_settings_overrides, get_project_anatomy_overrides, @@ -384,7 +384,7 @@ class SystemWidget(SettingsCategoryWidget): system_values = lib.NOT_SET else: system_values = lib.convert_overrides_to_gui_data( - {self.main_schema_key: get_studio_system_settings()} + {self.main_schema_key: get_studio_overrides_system_settings()} ) for input_field in self.input_fields: @@ -609,8 +609,12 @@ class ProjectWidget(SettingsCategoryWidget): else: studio_values = lib.convert_overrides_to_gui_data({ self.main_schema_key: { - PROJECT_SETTINGS_KEY: get_studio_project_settings(), - PROJECT_ANATOMY_KEY: get_studio_project_anatomy() + PROJECT_SETTINGS_KEY: ( + get_studio_overrides_default_project_settings() + ), + PROJECT_ANATOMY_KEY: ( + get_studio_overrides_default_project_anatomy() + ) } }) From a562e0c3bc1f3132bc538eed38f385ff6c69ab2f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 11:22:46 +0100 Subject: [PATCH 214/279] fixed docstring --- pype/settings/lib.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index 1b98ce19aa..0b830dd5ab 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -287,9 +287,9 @@ def save_project_settings(project_name, overrides): Do not use to store whole project settings data with defaults but only it's overrides with metadata defining how overrides should be applied in load - function. For loading should be used function `get_studio_project_settings` - for global project settings and `get_project_settings_overrides` for - project specific settings. + function. For loading should be used function + `get_studio_overrides_default_project_settings` for global project settings + and `get_project_settings_overrides` for project specific settings. Args: project_name(str, null): Project name for which overrides are @@ -358,8 +358,6 @@ def get_project_settings_overrides(project_name): Returns: dict: Only overrides for entered project, may be empty dictionary. """ - if not project_name: - return {} path_to_json = path_to_project_settings(project_name) if not os.path.exists(path_to_json): From 025cf4e8cc2c9a2a075f02b5c0e3676d261f25c3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 11:23:30 +0100 Subject: [PATCH 215/279] added function to get current context project settings `get_current_project_settings` --- pype/api.py | 2 ++ pype/settings/__init__.py | 2 ++ pype/settings/lib.py | 16 ++++++++++++++++ 3 files changed, 20 insertions(+) diff --git a/pype/api.py b/pype/api.py index 34e2c79845..3854da6d30 100644 --- a/pype/api.py +++ b/pype/api.py @@ -1,6 +1,7 @@ from .settings import ( get_system_settings, get_project_settings, + get_current_project_settings, get_anatomy_data, get_environments ) @@ -53,6 +54,7 @@ from .lib import _subprocess as subprocess __all__ = [ "get_system_settings", "get_project_settings", + "get_current_project_settings", "get_anatomy_data", "get_environments", diff --git a/pype/settings/__init__.py b/pype/settings/__init__.py index 2f487038bd..479236b99a 100644 --- a/pype/settings/__init__.py +++ b/pype/settings/__init__.py @@ -1,6 +1,7 @@ from .lib import ( get_system_settings, get_project_settings, + get_current_project_settings, get_anatomy_data, get_environments ) @@ -8,6 +9,7 @@ from .lib import ( __all__ = ( "get_system_settings", "get_project_settings", + "get_current_project_settings", "get_anatomy_data", "get_environments" ) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index 0b830dd5ab..23e303556e 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -464,6 +464,22 @@ def get_project_settings(project_name): return apply_overrides(studio_overrides, project_overrides) +def get_current_project_settings(): + """Project settings for current context project. + + Project name should be stored in environment variable `AVALON_PROJECT`. + This function should be used only in host context where environment + variable must be set and should not happen that any part of process will + change the value of the enviornment variable. + """ + project_name = os.environ.get("AVALON_PROJECT") + if not project_name: + raise ValueError( + "Missing context project in environemt variable `AVALON_PROJECT`." + ) + return get_project_settings(project_name) + + def get_environments(): """Calculated environment based on defaults and system settings. From 09c846023e218b6c7108b25513910d8355f51d27 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 11:49:41 +0100 Subject: [PATCH 216/279] workfiles build from settings --- pype/lib/avalon_context.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pype/lib/avalon_context.py b/pype/lib/avalon_context.py index 6cecdb93e3..c984e47b91 100644 --- a/pype/lib/avalon_context.py +++ b/pype/lib/avalon_context.py @@ -5,7 +5,7 @@ import logging import collections from avalon import io, pipeline -from ..api import config +from ..api import project_settings import avalon.api log = logging.getLogger("AvalonContext") @@ -410,12 +410,12 @@ class BuildWorkfile: (dict): preset per entered task name """ host_name = avalon.api.registered_host().__name__.rsplit(".", 1)[-1] - presets = config.get_presets(io.Session["AVALON_PROJECT"]) + presets = project_settings(io.Session["AVALON_PROJECT"]) # Get presets for host build_presets = ( - presets["plugins"] - .get(host_name, {}) + presets.get(host_name, {}) .get("workfile_build") + .get("profiles") ) if not build_presets: return From 81c56a45d625b1919ecbdab62db38dce6321ba6b Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 11:50:27 +0100 Subject: [PATCH 217/279] publish filters from settings --- pype/tools/pyblish_pype/control.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pype/tools/pyblish_pype/control.py b/pype/tools/pyblish_pype/control.py index fecfffd821..0994e25d4a 100644 --- a/pype/tools/pyblish_pype/control.py +++ b/pype/tools/pyblish_pype/control.py @@ -22,7 +22,7 @@ import pyblish.version from . import util from .constants import InstanceStates -from pype.api import config +from pype.api import project_settings class IterationBreak(Exception): @@ -121,14 +121,14 @@ class Controller(QtCore.QObject): def presets_by_hosts(self): # Get global filters as base - presets = config.get_presets().get("plugins", {}) + presets = project_settings(os.environ['AVALON_PROJECT']) or {} if not presets: return {} - result = presets.get("global", {}).get("filter", {}) + result = presets.get("global", {}).get("filters", {}) hosts = pyblish.api.registered_hosts() for host in hosts: - host_presets = presets.get(host, {}).get("filter") + host_presets = presets.get(host, {}).get("filters") if not host_presets: continue From f577480745639585f1d1caf70b52dfb0ff0e5368 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 11:50:47 +0100 Subject: [PATCH 218/279] publish intents from settings --- pype/tools/pyblish_pype/model.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pype/tools/pyblish_pype/model.py b/pype/tools/pyblish_pype/model.py index ec9689381e..8c9bc07d7e 100644 --- a/pype/tools/pyblish_pype/model.py +++ b/pype/tools/pyblish_pype/model.py @@ -35,7 +35,7 @@ from six import text_type from .vendor import qtawesome from .constants import PluginStates, InstanceStates, GroupStates, Roles -from pype.api import config +from pype.api import system_settings # ItemTypes @@ -104,8 +104,9 @@ class IntentModel(QtGui.QStandardItemModel): self.default_index = 0 intents_preset = ( - config.get_presets() - .get("global", {}) + system_settings() + .get("modules", {}) + .get("Ftrack", {}) .get("intent", {}) ) From 650d63081314730b32a95adf1ee5b55ca6ce7127 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 11:51:03 +0100 Subject: [PATCH 219/279] change intent settings to group --- .../gui_schemas/system_schema/module_settings/schema_ftrack.json | 1 + 1 file changed, 1 insertion(+) diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json b/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json index fa4cd3eea8..58cd81f544 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/module_settings/schema_ftrack.json @@ -59,6 +59,7 @@ "type": "dict", "label": "Intent", "collapsable_key": true, + "is_group": true, "children": [ { "type": "label", From 68002362e4f8233cf4806111634e0d1808fd7d43 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 11:53:39 +0100 Subject: [PATCH 220/279] nuke load mov outputs from settings --- pype/plugins/nuke/load/load_mov.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pype/plugins/nuke/load/load_mov.py b/pype/plugins/nuke/load/load_mov.py index d252aaa09d..078127ee42 100644 --- a/pype/plugins/nuke/load/load_mov.py +++ b/pype/plugins/nuke/load/load_mov.py @@ -4,7 +4,7 @@ import contextlib from avalon import api, io from pype.hosts.nuke import presets -from pype.api import config +from pype.api import project_settings @contextlib.contextmanager @@ -73,7 +73,8 @@ def add_review_presets_config(): "families": list(), "representations": list() } - review_presets = config.get_presets()["plugins"]["global"]["publish"].get( + settings = project_settings(io.Session["AVALON_PROJECT"]) + review_presets = settings["global"]["publish"].get( "ExtractReview", {}) outputs = review_presets.get("outputs", {}) From 15daa17544fe7b38a2e63eb4ef4c07902677a3cb Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 12:00:55 +0100 Subject: [PATCH 221/279] standalone publish families from settings --- .../tools/standalonepublish/widgets/widget_family.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pype/tools/standalonepublish/widgets/widget_family.py b/pype/tools/standalonepublish/widgets/widget_family.py index 1c8f2238fc..be68e411fd 100644 --- a/pype/tools/standalonepublish/widgets/widget_family.py +++ b/pype/tools/standalonepublish/widgets/widget_family.py @@ -1,10 +1,11 @@ +import os from collections import namedtuple from Qt import QtWidgets, QtCore from . import HelpRole, FamilyRole, ExistsRole, PluginRole, PluginKeyRole from . import FamilyDescriptionWidget -from pype.api import config +from pype.api import project_settings class FamilyWidget(QtWidgets.QWidget): @@ -309,9 +310,14 @@ class FamilyWidget(QtWidgets.QWidget): def refresh(self): has_families = False - presets = config.get_presets().get('standalone_publish', {}) + settings = project_settings(os.environ['AVALON_PROJECT']) + sp_settings = settings.get('standalonepublisher', {}) + print(sp_settings) + + for key, creator in sp_settings.get("create", {}).items(): + if key == "__dynamic_keys_labels__": + continue - for key, creator in presets.get('families', {}).items(): creator = namedtuple("Creator", creator.keys())(*creator.values()) label = creator.label or creator.family From 8e6abe759af6626078dae5f46b9bf72b6873a7c2 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 12:01:10 +0100 Subject: [PATCH 222/279] mark legacy review for removal --- pype/scripts/otio_burnin.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pype/scripts/otio_burnin.py b/pype/scripts/otio_burnin.py index 8da1dd8616..0bd636c6c5 100644 --- a/pype/scripts/otio_burnin.py +++ b/pype/scripts/otio_burnin.py @@ -429,6 +429,7 @@ def burnins_from_data( """ # Use legacy processing when options are not set + # TODO: remove legacy review if options is None or burnin_values is None: presets = config.get_presets().get("tools", {}).get("burnins", {}) options = presets.get("options") From 6c128049370bed0e6f695f5232874a126d3f7999 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 12:06:26 +0100 Subject: [PATCH 223/279] maya project shelves from settings --- setup/maya/userSetup.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup/maya/userSetup.py b/setup/maya/userSetup.py index bbf66846da..3cf2718796 100644 --- a/setup/maya/userSetup.py +++ b/setup/maya/userSetup.py @@ -1,5 +1,5 @@ import os -from pype.api import config +from pype.api import project_settings import pype.hosts.maya.lib as mlib from maya import cmds @@ -7,14 +7,14 @@ from maya import cmds print("starting PYPE usersetup") # build a shelf -presets = config.get_presets() -shelf_preset = presets['maya'].get('project_shelf') +settings = project_settings(os.environ['AVALON_PROJECT']) +shelf_preset = settings['maya'].get('project_shelf') if shelf_preset: project = os.environ["AVALON_PROJECT"] - icon_path = os.path.join(os.environ['PYPE_PROJECT_SCRIPTS'], project,"icons") + icon_path = os.path.join(os.environ['PYPE_PROJECT_SCRIPTS'], project, "icons") icon_path = os.path.abspath(icon_path) for i in shelf_preset['imports']: From 26a60111a6664ab9bd19f33af7bf8916933f3cde Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 12:40:51 +0100 Subject: [PATCH 224/279] remove status setting from application actionas was moved to prelaunch hook --- .../ftrack/actions/action_applications.py | 50 ------------------- 1 file changed, 50 deletions(-) diff --git a/pype/modules/ftrack/actions/action_applications.py b/pype/modules/ftrack/actions/action_applications.py index a75b581ce3..d488bd20a2 100644 --- a/pype/modules/ftrack/actions/action_applications.py +++ b/pype/modules/ftrack/actions/action_applications.py @@ -1,7 +1,6 @@ import os from uuid import uuid4 -from pype.api import config from pype.modules.ftrack.lib import BaseAction from pype.lib import ( ApplicationManager, @@ -205,55 +204,6 @@ class AppplicationsAction(BaseAction): "message": msg } - # TODO Move to prelaunch/afterlaunch hooks - # TODO change to settings - # Change status of task to In progress - presets = config.get_presets()["ftrack"]["ftrack_config"] - - if "status_update" in presets: - statuses = presets["status_update"] - - actual_status = entity["status"]["name"].lower() - already_tested = [] - ent_path = "/".join( - [ent["name"] for ent in entity["link"]] - ) - while True: - next_status_name = None - for key, value in statuses.items(): - if key in already_tested: - continue - if actual_status in value or "_any_" in value: - if key != "_ignore_": - next_status_name = key - already_tested.append(key) - break - already_tested.append(key) - - if next_status_name is None: - break - - try: - query = "Status where name is \"{}\"".format( - next_status_name - ) - status = session.query(query).one() - - entity["status"] = status - session.commit() - self.log.debug("Changing status to \"{}\" <{}>".format( - next_status_name, ent_path - )) - break - - except Exception: - session.rollback() - msg = ( - "Status \"{}\" in presets wasn't found" - " on Ftrack entity type \"{}\"" - ).format(next_status_name, entity.entity_type) - self.log.warning(msg) - return { "success": True, "message": "Launching {0}".format(self.label) From 6f3fe954051eb448a3691bc0f1279d50d421aaed Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 12:58:20 +0100 Subject: [PATCH 225/279] application is used everywhere so removed a lot of code --- pype/lib/applications.py | 388 +----------------- .../actions/action_application_loader.py | 104 ----- .../ftrack/actions/action_applications.py | 6 +- .../actions/action_create_cust_attrs.py | 71 +--- pype/modules/ftrack/lib/avalon_sync.py | 44 +- pype/modules/ftrack/lib/ftrack_app_handler.py | 223 ---------- pype/tools/launcher/lib.py | 47 --- pype/tools/launcher/models.py | 12 +- 8 files changed, 18 insertions(+), 877 deletions(-) delete mode 100644 pype/modules/ftrack/actions/action_application_loader.py delete mode 100644 pype/modules/ftrack/lib/ftrack_app_handler.py diff --git a/pype/lib/applications.py b/pype/lib/applications.py index ddff9ddcd2..0f2ea42175 100644 --- a/pype/lib/applications.py +++ b/pype/lib/applications.py @@ -1,6 +1,4 @@ import os -import sys -import getpass import copy import platform import inspect @@ -10,25 +8,14 @@ import distutils.spawn from abc import ABCMeta, abstractmethod import six -import acre -import avalon.lib -import avalon.api +from pype.settings import system_settings, environemtns +from ..api import Logger -from ..api import ( - Anatomy, - Logger, - config, - system_settings, - environments -) from .python_module_tools import ( modules_from_path, classes_from_module ) -from .hooks import execute_hook -from .deprecated import get_avalon_database - log = logging.getLogger(__name__) @@ -79,377 +66,6 @@ class ApplicationLaunchFailed(Exception): pass -def launch_application(project_name, asset_name, task_name, app_name): - """Launch host application with filling required environments. - - TODO(iLLiCiT): This should be split into more parts. - """ - # `get_avalon_database` is in Pype 3 replaced with using `AvalonMongoDB` - database = get_avalon_database() - project_document = database[project_name].find_one({"type": "project"}) - asset_document = database[project_name].find_one({ - "type": "asset", - "name": asset_name - }) - - asset_doc_parents = asset_document["data"].get("parents") - hierarchy = "/".join(asset_doc_parents) - - app_def = avalon.lib.get_application(app_name) - app_label = app_def.get("ftrack_label", app_def.get("label", app_name)) - - host_name = app_def["application_dir"] - # Workfile data collection may be special function? - data = { - "project": { - "name": project_document["name"], - "code": project_document["data"].get("code") - }, - "task": task_name, - "asset": asset_name, - "app": host_name, - "hierarchy": hierarchy - } - - try: - anatomy = Anatomy(project_name) - anatomy_filled = anatomy.format(data) - workdir = os.path.normpath(anatomy_filled["work"]["folder"]) - - except Exception as exc: - raise ApplicationLaunchFailed( - "Error in anatomy.format: {}".format(str(exc)) - ) - - try: - os.makedirs(workdir) - except FileExistsError: - pass - - last_workfile_path = None - extensions = avalon.api.HOST_WORKFILE_EXTENSIONS.get(host_name) - if extensions: - # Find last workfile - file_template = anatomy.templates["work"]["file"] - data.update({ - "version": 1, - "user": os.environ.get("PYPE_USERNAME") or getpass.getuser(), - "ext": extensions[0] - }) - - last_workfile_path = avalon.api.last_workfile( - workdir, file_template, data, extensions, True - ) - - # set environments for Avalon - prep_env = copy.deepcopy(os.environ) - prep_env.update({ - "AVALON_PROJECT": project_name, - "AVALON_ASSET": asset_name, - "AVALON_TASK": task_name, - "AVALON_APP": host_name, - "AVALON_APP_NAME": app_name, - "AVALON_HIERARCHY": hierarchy, - "AVALON_WORKDIR": workdir - }) - - start_last_workfile = avalon.api.should_start_last_workfile( - project_name, host_name, task_name - ) - # Store boolean as "0"(False) or "1"(True) - prep_env["AVALON_OPEN_LAST_WORKFILE"] = ( - str(int(bool(start_last_workfile))) - ) - - if ( - start_last_workfile - and last_workfile_path - and os.path.exists(last_workfile_path) - ): - prep_env["AVALON_LAST_WORKFILE"] = last_workfile_path - - prep_env.update(anatomy.roots_obj.root_environments()) - - # collect all the 'environment' attributes from parents - tools_attr = [prep_env["AVALON_APP"], prep_env["AVALON_APP_NAME"]] - tools_env = asset_document["data"].get("tools_env") or [] - tools_attr.extend(tools_env) - - tools_env = acre.get_tools(tools_attr) - env = acre.compute(tools_env) - env = acre.merge(env, current_env=dict(prep_env)) - - # Get path to execute - st_temp_path = os.environ["PYPE_CONFIG"] - os_plat = platform.system().lower() - - # Path to folder with launchers - path = os.path.join(st_temp_path, "launchers", os_plat) - - # Full path to executable launcher - execfile = None - - launch_hook = app_def.get("launch_hook") - if launch_hook: - log.info("launching hook: {}".format(launch_hook)) - ret_val = execute_hook(launch_hook, env=env) - if not ret_val: - raise ApplicationLaunchFailed( - "Hook didn't finish successfully {}".format(app_label) - ) - - if sys.platform == "win32": - for ext in os.environ["PATHEXT"].split(os.pathsep): - fpath = os.path.join(path.strip('"'), app_def["executable"] + ext) - if os.path.isfile(fpath) and os.access(fpath, os.X_OK): - execfile = fpath - break - - # Run SW if was found executable - if execfile is None: - raise ApplicationLaunchFailed( - "We didn't find launcher for {}".format(app_label) - ) - - popen = avalon.lib.launch( - executable=execfile, args=[], environment=env - ) - - elif ( - sys.platform.startswith("linux") - or sys.platform.startswith("darwin") - ): - execfile = os.path.join(path.strip('"'), app_def["executable"]) - # Run SW if was found executable - if execfile is None: - raise ApplicationLaunchFailed( - "We didn't find launcher for {}".format(app_label) - ) - - if not os.path.isfile(execfile): - raise ApplicationLaunchFailed( - "Launcher doesn't exist - {}".format(execfile) - ) - - try: - fp = open(execfile) - except PermissionError as perm_exc: - raise ApplicationLaunchFailed( - "Access denied on launcher {} - {}".format(execfile, perm_exc) - ) - - fp.close() - # check executable permission - if not os.access(execfile, os.X_OK): - raise ApplicationLaunchFailed( - "No executable permission - {}".format(execfile) - ) - - popen = avalon.lib.launch( # noqa: F841 - "/usr/bin/env", args=["bash", execfile], environment=env - ) - return popen - - -class ApplicationAction: - """Default application launcher - - This is a convenience application Action that when "config" refers to a - parsed application `.toml` this can launch the application. - - """ - _log = None - config = None - group = None - variant = None - required_session_keys = ( - "AVALON_PROJECT", - "AVALON_ASSET", - "AVALON_TASK" - ) - - @property - def log(self): - if self._log is None: - self._log = Logger().get_logger(self.__class__.__name__) - return self._log - - def is_compatible(self, session): - for key in self.required_session_keys: - if key not in session: - return False - return True - - def process(self, session, **kwargs): - """Process the full Application action""" - - project_name = session["AVALON_PROJECT"] - asset_name = session["AVALON_ASSET"] - task_name = session["AVALON_TASK"] - launch_application( - project_name, asset_name, task_name, self.name - ) - - self._ftrack_after_launch_procedure( - project_name, asset_name, task_name - ) - - def _ftrack_after_launch_procedure( - self, project_name, asset_name, task_name - ): - # TODO move to launch hook - required_keys = ("FTRACK_SERVER", "FTRACK_API_USER", "FTRACK_API_KEY") - for key in required_keys: - if not os.environ.get(key): - self.log.debug(( - "Missing required environment \"{}\"" - " for Ftrack after launch procedure." - ).format(key)) - return - - try: - import ftrack_api - session = ftrack_api.Session(auto_connect_event_hub=True) - self.log.debug("Ftrack session created") - except Exception: - self.log.warning("Couldn't create Ftrack session") - return - - try: - entity = self._find_ftrack_task_entity( - session, project_name, asset_name, task_name - ) - self._ftrack_status_change(session, entity, project_name) - self._start_timer(session, entity, ftrack_api) - except Exception: - self.log.warning( - "Couldn't finish Ftrack procedure.", exc_info=True - ) - return - - finally: - session.close() - - def _find_ftrack_task_entity( - self, session, project_name, asset_name, task_name - ): - project_entity = session.query( - "Project where full_name is \"{}\"".format(project_name) - ).first() - if not project_entity: - self.log.warning( - "Couldn't find project \"{}\" in Ftrack.".format(project_name) - ) - return - - potential_task_entities = session.query(( - "TypedContext where parent.name is \"{}\" and project_id is \"{}\"" - ).format(asset_name, project_entity["id"])).all() - filtered_entities = [] - for _entity in potential_task_entities: - if ( - _entity.entity_type.lower() == "task" - and _entity["name"] == task_name - ): - filtered_entities.append(_entity) - - if not filtered_entities: - self.log.warning(( - "Couldn't find task \"{}\" under parent \"{}\" in Ftrack." - ).format(task_name, asset_name)) - return - - if len(filtered_entities) > 1: - self.log.warning(( - "Found more than one task \"{}\"" - " under parent \"{}\" in Ftrack." - ).format(task_name, asset_name)) - return - - return filtered_entities[0] - - def _ftrack_status_change(self, session, entity, project_name): - presets = config.get_presets(project_name)["ftrack"]["ftrack_config"] - statuses = presets.get("status_update") - if not statuses: - return - - actual_status = entity["status"]["name"].lower() - already_tested = set() - ent_path = "/".join( - [ent["name"] for ent in entity["link"]] - ) - while True: - next_status_name = None - for key, value in statuses.items(): - if key in already_tested: - continue - if actual_status in value or "_any_" in value: - if key != "_ignore_": - next_status_name = key - already_tested.add(key) - break - already_tested.add(key) - - if next_status_name is None: - break - - try: - query = "Status where name is \"{}\"".format( - next_status_name - ) - status = session.query(query).one() - - entity["status"] = status - session.commit() - self.log.debug("Changing status to \"{}\" <{}>".format( - next_status_name, ent_path - )) - break - - except Exception: - session.rollback() - msg = ( - "Status \"{}\" in presets wasn't found" - " on Ftrack entity type \"{}\"" - ).format(next_status_name, entity.entity_type) - self.log.warning(msg) - - def _start_timer(self, session, entity, _ftrack_api): - self.log.debug("Triggering timer start.") - - user_entity = session.query("User where username is \"{}\"".format( - os.environ["FTRACK_API_USER"] - )).first() - if not user_entity: - self.log.warning( - "Couldn't find user with username \"{}\" in Ftrack".format( - os.environ["FTRACK_API_USER"] - ) - ) - return - - source = { - "user": { - "id": user_entity["id"], - "username": user_entity["username"] - } - } - event_data = { - "actionIdentifier": "start.timer", - "selection": [{"entityId": entity["id"], "entityType": "task"}] - } - session.event_hub.publish( - _ftrack_api.event.base.Event( - topic="ftrack.action.launch", - data=event_data, - source=source - ), - on_error="ignore" - ) - self.log.debug("Timer start triggered successfully.") - - # Special naming case for subprocess since its a built-in method. def _subprocess(*args, **kwargs): """Convenience method for getting output errors for subprocess. diff --git a/pype/modules/ftrack/actions/action_application_loader.py b/pype/modules/ftrack/actions/action_application_loader.py deleted file mode 100644 index 8749f89555..0000000000 --- a/pype/modules/ftrack/actions/action_application_loader.py +++ /dev/null @@ -1,104 +0,0 @@ -import os -import toml -import time -from pype.modules.ftrack.lib import AppAction -from avalon import lib -from pype.api import Logger, config - -log = Logger().get_logger(__name__) - - -def registerApp(app, session, plugins_presets): - name = app['name'] - variant = "" - try: - variant = app['name'].split("_")[1] - except Exception: - pass - - abspath = lib.which_app(app['name']) - if abspath is None: - log.error( - "'{0}' - App don't have config toml file".format(app['name']) - ) - return - - apptoml = toml.load(abspath) - - ''' REQUIRED ''' - executable = apptoml['executable'] - - ''' OPTIONAL ''' - label = apptoml.get('ftrack_label', app.get('label', name)) - icon = apptoml.get('ftrack_icon', None) - description = apptoml.get('description', None) - preactions = apptoml.get('preactions', []) - - if icon: - icon = icon.format(os.environ.get('PYPE_STATICS_SERVER', '')) - - # register action - AppAction( - session, label, name, executable, variant, - icon, description, preactions, plugins_presets - ).register() - - if not variant: - log.info('- Variant is not set') - - -def register(session, plugins_presets={}): - from pype.lib import env_value_to_bool - if env_value_to_bool("PYPE_USE_APP_MANAGER", default=False): - return - - app_usages = ( - config.get_presets() - .get("global", {}) - .get("applications") - ) or {} - - apps = [] - missing_app_names = [] - launchers_path = os.path.join(os.environ["PYPE_CONFIG"], "launchers") - for file in os.listdir(launchers_path): - filename, ext = os.path.splitext(file) - if ext.lower() != ".toml": - continue - - app_usage = app_usages.get(filename) - if not app_usage: - if app_usage is None: - missing_app_names.append(filename) - continue - - loaded_data = toml.load(os.path.join(launchers_path, file)) - app_data = { - "name": filename, - "label": loaded_data.get("label", filename) - } - apps.append(app_data) - - if missing_app_names: - log.debug( - "Apps not defined in applications usage. ({})".format( - ", ".join(( - "\"{}\"".format(app_name) - for app_name in missing_app_names - )) - ) - ) - - apps = sorted(apps, key=lambda app: app["name"]) - app_counter = 0 - for app in apps: - try: - registerApp(app, session, plugins_presets) - if app_counter % 5 == 0: - time.sleep(0.1) - app_counter += 1 - except Exception as exc: - log.warning( - "\"{}\" - not a proper App ({})".format(app['name'], str(exc)), - exc_info=True - ) diff --git a/pype/modules/ftrack/actions/action_applications.py b/pype/modules/ftrack/actions/action_applications.py index d488bd20a2..cf047a658d 100644 --- a/pype/modules/ftrack/actions/action_applications.py +++ b/pype/modules/ftrack/actions/action_applications.py @@ -211,7 +211,5 @@ class AppplicationsAction(BaseAction): def register(session, plugins_presets=None): - '''Register action. Called when used as an event plugin.''' - from pype.lib import env_value_to_bool - if env_value_to_bool("PYPE_USE_APP_MANAGER", default=False): - AppplicationsAction(session, plugins_presets).register() + """Register action. Called when used as an event plugin.""" + AppplicationsAction(session, plugins_presets).register() diff --git a/pype/modules/ftrack/actions/action_create_cust_attrs.py b/pype/modules/ftrack/actions/action_create_cust_attrs.py index 11931a5b30..d2d60df43e 100644 --- a/pype/modules/ftrack/actions/action_create_cust_attrs.py +++ b/pype/modules/ftrack/actions/action_create_cust_attrs.py @@ -146,9 +146,6 @@ class CustomAttributes(BaseAction): "text", "boolean", "date", "enumerator", "dynamic enumerator", "number" ) - # Pype 3 features - use_app_manager = env_value_to_bool("PYPE_USE_APP_MANAGER", default=False) - app_manager = None def discover(self, session, entities, event): ''' @@ -171,8 +168,7 @@ class CustomAttributes(BaseAction): }) session.commit() - if self.use_app_manager: - self.app_manager = ApplicationManager() + self.app_manager = ApplicationManager() try: self.prepare_global_data(session) @@ -391,54 +387,8 @@ class CustomAttributes(BaseAction): app_definitions.append({"empty": "< Empty >"}) return app_definitions - def application_definitions(self): - app_usages = self.presets.get("global", {}).get("applications") or {} - - app_definitions = [] - launchers_path = os.path.join(os.environ["PYPE_CONFIG"], "launchers") - - missing_app_names = [] - for file in os.listdir(launchers_path): - app_name, ext = os.path.splitext(file) - if ext.lower() != ".toml": - continue - - if not app_usages.get(app_name): - missing_app_names.append(app_name) - continue - - loaded_data = toml.load(os.path.join(launchers_path, file)) - - ftrack_label = loaded_data.get("ftrack_label") - if ftrack_label: - parts = app_name.split("_") - if len(parts) > 1: - ftrack_label = " ".join((ftrack_label, parts[-1])) - else: - ftrack_label = loaded_data.get("label", app_name) - - app_definitions.append({app_name: ftrack_label}) - - if missing_app_names: - self.log.warning( - "Apps not defined in applications usage. ({})".format( - ", ".join(( - "\"{}\"".format(app_name) - for app_name in missing_app_names - )) - ) - ) - - # Make sure there is at least one item - if not app_definitions: - app_definitions.append({"empty": "< Empty >"}) - return app_definitions - def applications_attribute(self, event): - if self.use_app_manager: - apps_data = self.app_defs_from_app_manager() - else: - apps_data = self.application_definitions() + apps_data = self.app_defs_from_app_manager() applications_custom_attr_data = { "label": "Applications", @@ -453,28 +403,13 @@ class CustomAttributes(BaseAction): } self.process_attr_data(applications_custom_attr_data, event) - def tools_from_app_manager(self): + def tools_attribute(self, event): tools_data = [] for tool_name, tool in self.app_manager.tools.items(): if tool.enabled: tools_data.append({ tool_name: tool_name }) - return tools_data - - def tools_data(self): - tool_usages = self.presets.get("global", {}).get("tools") or {} - tools_data = [] - for tool_name, usage in tool_usages.items(): - if usage: - tools_data.append({tool_name: tool_name}) - return tools_data - - def tools_attribute(self, event): - if self.use_app_manager: - tools_data = self.tools_from_app_manager() - else: - tools_data = self.tools_data() # Make sure there is at least one item if not tools_data: diff --git a/pype/modules/ftrack/lib/avalon_sync.py b/pype/modules/ftrack/lib/avalon_sync.py index 97116317af..c2bc6d2b29 100644 --- a/pype/modules/ftrack/lib/avalon_sync.py +++ b/pype/modules/ftrack/lib/avalon_sync.py @@ -191,43 +191,17 @@ def get_project_apps(in_app_list): apps = [] warnings = collections.defaultdict(list) - if env_value_to_bool("PYPE_USE_APP_MANAGER", default=False): - missing_app_msg = "Missing definition of application" - application_manager = ApplicationManager() - for app_name in in_app_list: - app = application_manager.applications.get(app_name) - if app: - apps.append({ - "name": app_name, - "label": app.full_label - }) - else: - warnings[missing_app_msg].append(app_name) - return apps, warnings - - # TODO report - missing_toml_msg = "Missing config file for application" - error_msg = ( - "Unexpected error happend during preparation of application" - ) - - for app in in_app_list: - try: - toml_path = avalon.lib.which_app(app) - if not toml_path: - log.warning(missing_toml_msg + ' "{}"'.format(app)) - warnings[missing_toml_msg].append(app) - continue - + missing_app_msg = "Missing definition of application" + application_manager = ApplicationManager() + for app_name in in_app_list: + app = application_manager.applications.get(app_name) + if app: apps.append({ - "name": app, - "label": toml.load(toml_path)["label"] + "name": app_name, + "label": app.full_label }) - except Exception: - warnings[error_msg].append(app) - log.warning(( - "Error has happened during preparing application \"{}\"" - ).format(app), exc_info=True) + else: + warnings[missing_app_msg].append(app_name) return apps, warnings diff --git a/pype/modules/ftrack/lib/ftrack_app_handler.py b/pype/modules/ftrack/lib/ftrack_app_handler.py deleted file mode 100644 index 23776aced7..0000000000 --- a/pype/modules/ftrack/lib/ftrack_app_handler.py +++ /dev/null @@ -1,223 +0,0 @@ -from pype import lib as pypelib -from pype.api import config -from .ftrack_action_handler import BaseAction - - -class AppAction(BaseAction): - """Application Action class. - - Args: - session (ftrack_api.Session): Session where action will be registered. - label (str): A descriptive string identifing your action. - varaint (str, optional): To group actions together, give them the same - label and specify a unique variant per action. - identifier (str): An unique identifier for app. - description (str): A verbose descriptive text for you action. - icon (str): Url path to icon which will be shown in Ftrack web. - """ - - type = "Application" - preactions = ["start.timer"] - - def __init__( - self, session, label, name, executable, variant=None, - icon=None, description=None, preactions=[], plugins_presets={} - ): - self.label = label - self.identifier = name - self.executable = executable - self.variant = variant - self.icon = icon - self.description = description - self.preactions.extend(preactions) - - super().__init__(session, plugins_presets) - if label is None: - raise ValueError("Action missing label.") - if name is None: - raise ValueError("Action missing identifier.") - if executable is None: - raise ValueError("Action missing executable.") - - def register(self): - """Registers the action, subscribing the discover and launch topics.""" - - discovery_subscription = ( - "topic=ftrack.action.discover and source.user.username={0}" - ).format(self.session.api_user) - - self.session.event_hub.subscribe( - discovery_subscription, - self._discover, - priority=self.priority - ) - - launch_subscription = ( - "topic=ftrack.action.launch" - " and data.actionIdentifier={0}" - " and source.user.username={1}" - ).format( - self.identifier, - self.session.api_user - ) - self.session.event_hub.subscribe( - launch_subscription, - self._launch - ) - - def discover(self, session, entities, event): - """Return true if we can handle the selected entities. - - Args: - session (ftrack_api.Session): Helps to query necessary data. - entities (list): Object of selected entities. - event (ftrack_api.Event): Ftrack event causing discover callback. - """ - - if ( - len(entities) != 1 - or entities[0].entity_type.lower() != "task" - ): - return False - - entity = entities[0] - if entity["parent"].entity_type.lower() == "project": - return False - - avalon_project_apps = event["data"].get("avalon_project_apps", None) - avalon_project_doc = event["data"].get("avalon_project_doc", None) - if avalon_project_apps is None: - if avalon_project_doc is None: - ft_project = self.get_project_from_entity(entity) - database = pypelib.get_avalon_database() - project_name = ft_project["full_name"] - avalon_project_doc = database[project_name].find_one({ - "type": "project" - }) or False - event["data"]["avalon_project_doc"] = avalon_project_doc - - if not avalon_project_doc: - return False - - project_apps_config = avalon_project_doc["config"].get("apps", []) - avalon_project_apps = [ - app["name"] for app in project_apps_config - ] or False - event["data"]["avalon_project_apps"] = avalon_project_apps - - if not avalon_project_apps: - return False - - return self.identifier in avalon_project_apps - - def _launch(self, event): - entities = self._translate_event(event) - - preactions_launched = self._handle_preactions( - self.session, event - ) - if preactions_launched is False: - return - - response = self.launch(self.session, entities, event) - - return self._handle_result(response) - - def launch(self, session, entities, event): - """Callback method for the custom action. - - return either a bool (True if successful or False if the action failed) - or a dictionary with they keys `message` and `success`, the message - should be a string and will be displayed as feedback to the user, - success should be a bool, True if successful or False if the action - failed. - - *session* is a `ftrack_api.Session` instance - - *entities* is a list of tuples each containing the entity type and - the entity id. If the entity is a hierarchical you will always get - the entity type TypedContext, once retrieved through a get operation - you will have the "real" entity type ie. example Shot, Sequence - or Asset Build. - - *event* the unmodified original event - """ - - entity = entities[0] - - task_name = entity["name"] - asset_name = entity["parent"]["name"] - project_name = entity["project"]["full_name"] - try: - pypelib.launch_application( - project_name, asset_name, task_name, self.identifier - ) - - except pypelib.ApplicationLaunchFailed as exc: - self.log.error(str(exc)) - return { - "success": False, - "message": str(exc) - } - - except Exception: - msg = "Unexpected failure of application launch {}".format( - self.label - ) - self.log.error(msg, exc_info=True) - return { - "success": False, - "message": msg - } - - # Change status of task to In progress - presets = config.get_presets()["ftrack"]["ftrack_config"] - - if "status_update" in presets: - statuses = presets["status_update"] - - actual_status = entity["status"]["name"].lower() - already_tested = [] - ent_path = "/".join( - [ent["name"] for ent in entity["link"]] - ) - while True: - next_status_name = None - for key, value in statuses.items(): - if key in already_tested: - continue - if actual_status in value or "_any_" in value: - if key != "_ignore_": - next_status_name = key - already_tested.append(key) - break - already_tested.append(key) - - if next_status_name is None: - break - - try: - query = "Status where name is \"{}\"".format( - next_status_name - ) - status = session.query(query).one() - - entity["status"] = status - session.commit() - self.log.debug("Changing status to \"{}\" <{}>".format( - next_status_name, ent_path - )) - break - - except Exception: - session.rollback() - msg = ( - "Status \"{}\" in presets wasn't found" - " on Ftrack entity type \"{}\"" - ).format(next_status_name, entity.entity_type) - self.log.warning(msg) - - return { - "success": True, - "message": "Launching {0}".format(self.label) - } diff --git a/pype/tools/launcher/lib.py b/pype/tools/launcher/lib.py index f70929fc2e..7d2a49db9d 100644 --- a/pype/tools/launcher/lib.py +++ b/pype/tools/launcher/lib.py @@ -16,60 +16,13 @@ provides a bridge between the file-based project inventory and configuration. import os from Qt import QtGui -from avalon import lib from avalon.vendor import qtawesome from pype.api import resources -from pype.lib import ApplicationAction ICON_CACHE = {} NOT_FOUND = type("NotFound", (object, ), {}) -def get_application_actions(project): - """Define dynamic Application classes for project using `.toml` files - - Args: - project (dict): project document from the database - - Returns: - list: list of dictionaries - """ - - apps = [] - for app in project["config"]["apps"]: - try: - app_name = app["name"] - app_definition = lib.get_application(app_name) - except Exception as exc: - print("Unable to load application: %s - %s" % (app['name'], exc)) - continue - - # Get from app definition, if not there from app in project - icon = app_definition.get("icon", app.get("icon", "folder-o")) - color = app_definition.get("color", app.get("color", None)) - order = app_definition.get("order", app.get("order", 0)) - label = app_definition.get("label") or app.get("label") or app_name - label_variant = app_definition.get("label_variant") - group = app_definition.get("group") or app.get("group") - action = type( - "app_{}".format(app_name), - (ApplicationAction,), - { - "name": app_name, - "label": label, - "label_variant": label_variant, - "group": group, - "icon": icon, - "color": color, - "order": order, - "config": app_definition.copy() - } - ) - - apps.append(action) - return apps - - def get_action_icon(action): icon_name = action.icon if not icon_name: diff --git a/pype/tools/launcher/models.py b/pype/tools/launcher/models.py index 07db36fa9a..81d6a455d5 100644 --- a/pype/tools/launcher/models.py +++ b/pype/tools/launcher/models.py @@ -117,11 +117,7 @@ class ActionModel(QtGui.QStandardItemModel): super(ActionModel, self).__init__(parent=parent) self.dbcon = dbcon - self.use_manager = env_value_to_bool( - "PYPE_USE_APP_MANAGER", default=False - ) - if self.use_manager: - self.application_manager = ApplicationManager() + self.application_manager = ApplicationManager() self._session = {} self._groups = {} @@ -141,11 +137,7 @@ class ActionModel(QtGui.QStandardItemModel): actions = api.discover(api.Action) # Get available project actions and the application actions - if self.use_manager: - app_actions = self.get_application_actions() - else: - project_doc = self.dbcon.find_one({"type": "project"}) - app_actions = lib.get_application_actions(project_doc) + app_actions = self.get_application_actions() actions.extend(app_actions) self._registered_actions = actions From d24ac5597aa5353402b6d7408c0a153131564243 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 12:59:18 +0100 Subject: [PATCH 226/279] removed deprecated from lib --- pype/lib/__init__.py | 5 ----- pype/lib/deprecated.py | 26 ---------------------- pype/tests/test_lib_restructuralization.py | 2 -- 3 files changed, 33 deletions(-) delete mode 100644 pype/lib/deprecated.py diff --git a/pype/lib/__init__.py b/pype/lib/__init__.py index ecdd155c99..5fec2b8069 100644 --- a/pype/lib/__init__.py +++ b/pype/lib/__init__.py @@ -1,11 +1,6 @@ # -*- coding: utf-8 -*- """Pype lib module.""" -from .deprecated import ( - get_avalon_database, - set_io_database -) - from .env_tools import ( env_value_to_bool, get_paths_from_environ diff --git a/pype/lib/deprecated.py b/pype/lib/deprecated.py deleted file mode 100644 index e7296f67ef..0000000000 --- a/pype/lib/deprecated.py +++ /dev/null @@ -1,26 +0,0 @@ -import os - -from avalon import io - - -def get_avalon_database(): - """Mongo database used in avalon's io. - - * Function is not used in pype 3.0 where was replaced with usage of - AvalonMongoDB. - """ - if io._database is None: - set_io_database() - return io._database - - -def set_io_database(): - """Set avalon's io context with environemnts. - - * Function is not used in pype 3.0 where was replaced with usage of - AvalonMongoDB. - """ - required_keys = ["AVALON_PROJECT", "AVALON_ASSET", "AVALON_SILO"] - for key in required_keys: - os.environ[key] = os.environ.get(key, "") - io.install() diff --git a/pype/tests/test_lib_restructuralization.py b/pype/tests/test_lib_restructuralization.py index 152be8d1eb..48370f5438 100644 --- a/pype/tests/test_lib_restructuralization.py +++ b/pype/tests/test_lib_restructuralization.py @@ -13,8 +13,6 @@ def test_backward_compatibility(printer): from pype.lib import ApplicationLaunchFailed from pype.lib import launch_application from pype.lib import ApplicationAction - from pype.lib import get_avalon_database - from pype.lib import set_io_database from pype.lib import get_ffmpeg_tool_path from pype.lib import get_last_version_from_path From db1c5b4a8db44badbf0f1ec43aefe8ec577d2a27 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 13:03:45 +0100 Subject: [PATCH 227/279] removed unused imports --- pype/modules/ftrack/actions/action_create_cust_attrs.py | 2 +- pype/modules/ftrack/lib/avalon_sync.py | 5 +---- pype/tools/launcher/models.py | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/pype/modules/ftrack/actions/action_create_cust_attrs.py b/pype/modules/ftrack/actions/action_create_cust_attrs.py index d2d60df43e..f76d794d6f 100644 --- a/pype/modules/ftrack/actions/action_create_cust_attrs.py +++ b/pype/modules/ftrack/actions/action_create_cust_attrs.py @@ -9,7 +9,7 @@ from pype.modules.ftrack.lib.avalon_sync import ( CUST_ATTR_ID_KEY, CUST_ATTR_GROUP, default_custom_attributes_definition ) from pype.api import config -from pype.lib import ApplicationManager, env_value_to_bool +from pype.lib import ApplicationManager """ This action creates/updates custom attributes. diff --git a/pype/modules/ftrack/lib/avalon_sync.py b/pype/modules/ftrack/lib/avalon_sync.py index c2bc6d2b29..671899a028 100644 --- a/pype/modules/ftrack/lib/avalon_sync.py +++ b/pype/modules/ftrack/lib/avalon_sync.py @@ -17,10 +17,7 @@ from bson.errors import InvalidId from pymongo import UpdateOne import ftrack_api from pype.api import config -from pype.lib import ( - ApplicationManager, - env_value_to_bool -) +from pype.lib import ApplicationManager log = Logger().get_logger(__name__) diff --git a/pype/tools/launcher/models.py b/pype/tools/launcher/models.py index 81d6a455d5..3e869f3e4a 100644 --- a/pype/tools/launcher/models.py +++ b/pype/tools/launcher/models.py @@ -7,7 +7,7 @@ from .actions import ApplicationAction from Qt import QtCore, QtGui from avalon.vendor import qtawesome from avalon import style, api -from pype.lib import ApplicationManager, env_value_to_bool +from pype.lib import ApplicationManager log = logging.getLogger(__name__) From ce8c200de1e806af4c8458f09c78559800b9e954 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 13:11:19 +0100 Subject: [PATCH 228/279] fixed imports --- pype/lib/__init__.py | 7 ------- pype/lib/applications.py | 2 +- pype/tests/test_lib_restructuralization.py | 2 -- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/pype/lib/__init__.py b/pype/lib/__init__.py index 5fec2b8069..d02d20ad4d 100644 --- a/pype/lib/__init__.py +++ b/pype/lib/__init__.py @@ -31,8 +31,6 @@ from .applications import ( ApplicationManager, PreLaunchHook, PostLaunchHook, - launch_application, - ApplicationAction, _subprocess ) @@ -50,9 +48,6 @@ from .ffmpeg_utils import ( ) __all__ = [ - "get_avalon_database", - "set_io_database", - "env_value_to_bool", "get_paths_from_environ", @@ -77,8 +72,6 @@ __all__ = [ "ApplicationManager", "PreLaunchHook", "PostLaunchHook", - "launch_application", - "ApplicationAction", "filter_pyblish_plugins", diff --git a/pype/lib/applications.py b/pype/lib/applications.py index 0f2ea42175..ea95fefea1 100644 --- a/pype/lib/applications.py +++ b/pype/lib/applications.py @@ -9,7 +9,7 @@ from abc import ABCMeta, abstractmethod import six -from pype.settings import system_settings, environemtns +from pype.settings import system_settings, environments from ..api import Logger from .python_module_tools import ( diff --git a/pype/tests/test_lib_restructuralization.py b/pype/tests/test_lib_restructuralization.py index 48370f5438..957167a8bf 100644 --- a/pype/tests/test_lib_restructuralization.py +++ b/pype/tests/test_lib_restructuralization.py @@ -11,8 +11,6 @@ def test_backward_compatibility(printer): from pype.lib import get_latest_version from pype.lib import ApplicationLaunchFailed - from pype.lib import launch_application - from pype.lib import ApplicationAction from pype.lib import get_ffmpeg_tool_path from pype.lib import get_last_version_from_path From 59ee5827517d57ba173043d22897c3f178a6ad6e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 13:18:49 +0100 Subject: [PATCH 229/279] removed unused logger --- pype/lib/applications.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/pype/lib/applications.py b/pype/lib/applications.py index ea95fefea1..abc6ca5017 100644 --- a/pype/lib/applications.py +++ b/pype/lib/applications.py @@ -2,7 +2,6 @@ import os import copy import platform import inspect -import logging import subprocess import distutils.spawn from abc import ABCMeta, abstractmethod @@ -17,8 +16,6 @@ from .python_module_tools import ( classes_from_module ) -log = logging.getLogger(__name__) - class ApplicationNotFound(Exception): """Application was not found in ApplicationManager by name.""" From f890fb74c5a386c5695e1e1d915774c78f8c1e53 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 13:32:52 +0100 Subject: [PATCH 230/279] removed unsused imports and modified docstring --- pype/modules/ftrack/lib/avalon_sync.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/pype/modules/ftrack/lib/avalon_sync.py b/pype/modules/ftrack/lib/avalon_sync.py index 671899a028..a379aa9900 100644 --- a/pype/modules/ftrack/lib/avalon_sync.py +++ b/pype/modules/ftrack/lib/avalon_sync.py @@ -8,8 +8,6 @@ import copy from avalon.api import AvalonMongoDB import avalon -import avalon.api -from avalon.vendor import toml from pype.api import Logger, Anatomy from bson.objectid import ObjectId @@ -175,15 +173,14 @@ def get_avalon_project_template(project_name): def get_project_apps(in_app_list): - """ - Returns metadata information about apps in 'in_app_list' enhanced - from toml files. + """ Application definitions for app name. + Args: in_app_list: (list) - names of applications Returns: - tuple (list, dictionary) - list of dictionaries about apps - dictionary of warnings + tuple (list, dictionary) - list of dictionaries with apps definitions + dictionary of warnings """ apps = [] warnings = collections.defaultdict(list) From 9575a721843e7198a4acdc2cccefa58248efeebc Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 13:41:12 +0100 Subject: [PATCH 231/279] remov ftrack json to lower filename --- .../defaults/project_settings/Ftrack.json | 98 ------------------- 1 file changed, 98 deletions(-) delete mode 100644 pype/settings/defaults/project_settings/Ftrack.json diff --git a/pype/settings/defaults/project_settings/Ftrack.json b/pype/settings/defaults/project_settings/Ftrack.json deleted file mode 100644 index 023b85cb3b..0000000000 --- a/pype/settings/defaults/project_settings/Ftrack.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "ftrack_actions_path": [], - "ftrack_events_path": [], - "events": { - "sync_to_avalon": { - "enabled": true, - "statuses_name_change": [ - "ready", - "not ready" - ] - }, - "push_frame_values_to_task": { - "enabled": true, - "interest_entity_types": [ - "shot", - "asset build" - ], - "interest_attributess": [ - "frameStart", - "frameEnd" - ] - }, - "thumbnail_updates": { - "enabled": true, - "levels": 2 - }, - "user_assignment": { - "enabled": true - }, - "status_update": { - "enabled": true, - "mapping": { - "In Progress": [ - "__any__" - ], - "Ready": [ - "Not Ready" - ], - "__ignore__": [ - "in prgoress", - "omitted", - "on hold" - ] - } - }, - "status_task_to_parent": { - "enabled": true, - "parent_status_match_all_task_statuses": { - "Completed": [ - "Approved", - "Omitted" - ] - }, - "parent_status_by_task_status": { - "In Progress": [ - "in progress", - "change requested", - "retake", - "pending review" - ] - } - }, - "status_task_to_version": { - "enabled": true, - "mapping": { - "Approved": [ - "Complete" - ] - } - }, - "status_version_to_task": { - "enabled": true, - "mapping": { - "Complete": [ - "Approved", - "Complete" - ] - } - }, - "first_version_status": { - "enabled": true, - "status": "" - }, - "next_task_update": { - "enabled": true, - "mapping": { - "Ready": "Not Ready" - } - } - }, - "publish": { - "IntegrateFtrackNote": { - "enabled": true, - "note_with_intent_template": "", - "note_labels": [] - } - } -} \ No newline at end of file From b97fbc2285ce1cf52e295f22e32d1d08557a633e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 13:43:34 +0100 Subject: [PATCH 232/279] moved back ftrack json file with lowered name and lowered key in schema --- .../defaults/project_settings/ftrack.json | 98 +++++++++++++++++++ .../schema_project_ftrack.json | 2 +- 2 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 pype/settings/defaults/project_settings/ftrack.json diff --git a/pype/settings/defaults/project_settings/ftrack.json b/pype/settings/defaults/project_settings/ftrack.json new file mode 100644 index 0000000000..4eabb52dc1 --- /dev/null +++ b/pype/settings/defaults/project_settings/ftrack.json @@ -0,0 +1,98 @@ +{ + "ftrack_actions_path": [], + "ftrack_events_path": [], + "events": { + "sync_to_avalon": { + "enabled": true, + "statuses_name_change": [ + "ready", + "not ready" + ] + }, + "push_frame_values_to_task": { + "enabled": true, + "interest_entity_types": [ + "shot", + "asset build" + ], + "interest_attributess": [ + "frameStart", + "frameEnd" + ] + }, + "thumbnail_updates": { + "enabled": true, + "levels": 2 + }, + "user_assignment": { + "enabled": true + }, + "status_update": { + "enabled": true, + "mapping": { + "In Progress": [ + "__any__" + ], + "Ready": [ + "Not Ready" + ], + "__ignore__": [ + "in prgoress", + "omitted", + "on hold" + ] + } + }, + "status_task_to_parent": { + "enabled": true, + "parent_status_match_all_task_statuses": { + "Completed": [ + "Approved", + "Omitted" + ] + }, + "parent_status_by_task_status": { + "In Progress": [ + "in progress", + "change requested", + "retake", + "pending review" + ] + } + }, + "status_task_to_version": { + "enabled": true, + "mapping": { + "Approved": [ + "Complete" + ] + } + }, + "status_version_to_task": { + "enabled": true, + "mapping": { + "Complete": [ + "Approved", + "Complete" + ] + } + }, + "first_version_status": { + "enabled": true, + "status": "" + }, + "next_task_update": { + "enabled": true, + "mapping": { + "Ready": "Not Ready" + } + } + }, + "publish": { + "IntegrateFtrackNote": { + "enabled": true, + "note_with_intent_template": "", + "note_labels": [] + } + } +} diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json index 3b784accc1..f54c1232a6 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json @@ -1,6 +1,6 @@ { "type": "dict", - "key": "Ftrack", + "key": "ftrack", "label": "Ftrack", "collapsable": true, "checkbox_key": "enabled", From 9515bcae3eb1b22f3fd19928119b0602a16ea6bb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 14:26:24 +0100 Subject: [PATCH 233/279] modified user assignment to use settings --- .../ftrack/events/event_user_assigment.py | 71 +++++++++++++------ 1 file changed, 49 insertions(+), 22 deletions(-) diff --git a/pype/modules/ftrack/events/event_user_assigment.py b/pype/modules/ftrack/events/event_user_assigment.py index 19a67b745f..bc05faa192 100644 --- a/pype/modules/ftrack/events/event_user_assigment.py +++ b/pype/modules/ftrack/events/event_user_assigment.py @@ -8,7 +8,7 @@ from avalon.api import AvalonMongoDB from bson.objectid import ObjectId -from pype.api import config, Anatomy +from pype.api import Anatomy, project_settings as get_project_settings class UserAssigmentEvent(BaseEvent): @@ -173,26 +173,50 @@ class UserAssigmentEvent(BaseEvent): return t_data def launch(self, session, event): - # load shell scripts presets - presets = config.get_presets()['ftrack'].get("user_assigment_event") - if not presets: + if not event.get("data"): return - for entity in event.get('data', {}).get('entities', []): - if entity.get('entity_type') != 'Appointment': + + entities_info = event["data"].get("entities") + if not entities_info: + return + + # load shell scripts presets + tmp_by_project_name = {} + for entity_info in entities_info: + if entity_info.get('entity_type') != 'Appointment': continue - task, user = self._get_task_and_user(session, - entity.get('action'), - entity.get('changes')) + task_entity, user_entity = self._get_task_and_user( + session, + entity_info.get('action'), + entity_info.get('changes') + ) - if not task or not user: - self.log.error( - 'Task or User was not found.') + if not task_entity or not user_entity: + self.log.error("Task or User was not found.") continue - data = self._get_template_data(task) # format directories to pass to shell script - anatomy = Anatomy(data["project"]["name"]) + project_name = task_entity["project"]["full_name"] + project_data = tmp_by_project_name.get(project_name) or {} + if "scripts_by_action" not in project_data: + project_settings = get_project_settings(project_name) + _settings = ( + project_settings["ftrack"]["events"]["user_assignment"] + ) + project_data["scripts_by_action"] = _settings.get("scripts") + tmp_by_project_name[project_name] = project_data + + scripts_by_action = project_data["scripts_by_action"] + if not scripts_by_action: + continue + + if "anatomy" not in project_data: + project_data["anatomy"] = Anatomy(project_name) + tmp_by_project_name[project_name] = project_data + + anatomy = project_data["anatomy"] + data = self._get_template_data(task_entity) anatomy_filled = anatomy.format(data) # formatting work dir is easiest part as we can use whole path work_dir = anatomy_filled["work"]["folder"] @@ -201,8 +225,10 @@ class UserAssigmentEvent(BaseEvent): publish = anatomy_filled["publish"]["folder"] # now find path to {asset} - m = re.search("(^.+?{})".format(data['asset']), - publish) + m = re.search( + "(^.+?{})".format(data["asset"]), + publish + ) if not m: msg = 'Cannot get part of publish path {}'.format(publish) @@ -213,12 +239,13 @@ class UserAssigmentEvent(BaseEvent): } publish_dir = m.group(1) - for script in presets.get(entity.get('action')): - self.log.info( - '[{}] : running script for user {}'.format( - entity.get('action'), user["username"])) - self._run_script(script, [user["username"], - work_dir, publish_dir]) + username = user_entity["username"] + event_entity_action = entity_info["action"] + for script in scripts_by_action.get(event_entity_action): + self.log.info(( + "[{}] : running script for user {}" + ).format(event_entity_action, username)) + self._run_script(script, [username, work_dir, publish_dir]) return True From e9892ce77ef68d4f8616cabb2124829ba149b6cb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 14:48:03 +0100 Subject: [PATCH 234/279] create project structure is using settings --- .../action_create_project_structure.py | 29 ++++++++++--------- .../ftrack/ftrack_server/ftrack_server.py | 4 ++- pype/modules/ftrack/lib/__init__.py | 4 +-- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/pype/modules/ftrack/actions/action_create_project_structure.py b/pype/modules/ftrack/actions/action_create_project_structure.py index 22190c16db..d5cb381a63 100644 --- a/pype/modules/ftrack/actions/action_create_project_structure.py +++ b/pype/modules/ftrack/actions/action_create_project_structure.py @@ -2,7 +2,7 @@ import os import re from pype.modules.ftrack.lib import BaseAction, statics_icon -from pype.api import config, Anatomy +from pype.api import Anatomy, project_settings as get_project_settings class CreateProjectFolders(BaseAction): @@ -69,25 +69,26 @@ class CreateProjectFolders(BaseAction): return True def launch(self, session, entities, event): - entity = entities[0] - project = self.get_project_from_entity(entity) - project_folder_presets = ( - config.get_presets() - .get("tools", {}) - .get("project_folder_structure") + # Get project entity + project_entity = self.get_project_from_entity(entities[0]) + # Load settings for project + project_name = project_entity["full_name"] + project_settings = get_project_settings(project_name) + project_folder_structure = ( + project_settings["global"]["project_folder_structure"] ) - if not project_folder_presets: + if not project_folder_structure: return { "success": False, - "message": "Project structure presets are not set." + "message": "Project structure is not set." } try: # Get paths based on presets - basic_paths = self.get_path_items(project_folder_presets) - anatomy = Anatomy(project["full_name"]) - self.create_folders(basic_paths, entity, project, anatomy) - self.create_ftrack_entities(basic_paths, project) + basic_paths = self.get_path_items(project_folder_structure) + anatomy = Anatomy(project_entity["full_name"]) + self.create_folders(basic_paths, project_entity, anatomy) + self.create_ftrack_entities(basic_paths, project_entity) except Exception as exc: session.rollback() @@ -219,7 +220,7 @@ class CreateProjectFolders(BaseAction): output.append(os.path.normpath(os.path.sep.join(clean_items))) return output - def create_folders(self, basic_paths, entity, project, anatomy): + def create_folders(self, basic_paths, project, anatomy): roots_paths = [] if isinstance(anatomy.roots, dict): for root in anatomy.roots: diff --git a/pype/modules/ftrack/ftrack_server/ftrack_server.py b/pype/modules/ftrack/ftrack_server/ftrack_server.py index 92f3c0b3a0..9940ab236e 100644 --- a/pype/modules/ftrack/ftrack_server/ftrack_server.py +++ b/pype/modules/ftrack/ftrack_server/ftrack_server.py @@ -2,10 +2,12 @@ import os import sys import types import importlib -import ftrack_api import time import logging import inspect + +import ftrack_api + from pype.api import Logger, config diff --git a/pype/modules/ftrack/lib/__init__.py b/pype/modules/ftrack/lib/__init__.py index a52e73d10f..3890eacf90 100644 --- a/pype/modules/ftrack/lib/__init__.py +++ b/pype/modules/ftrack/lib/__init__.py @@ -3,7 +3,6 @@ from . import credentials from .ftrack_base_handler import BaseHandler from .ftrack_event_handler import BaseEvent from .ftrack_action_handler import BaseAction, ServerAction, statics_icon -from .ftrack_app_handler import AppAction __all__ = ( "avalon_sync", @@ -12,6 +11,5 @@ __all__ = ( "BaseEvent", "BaseAction", "ServerAction", - "statics_icon", - "AppAction" + "statics_icon" ) From 72d3cc6e8b23ae3b9bf467e072aad4b933bd17c8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 15:21:28 +0100 Subject: [PATCH 235/279] event handler VersionToTaskStatus is using settings --- .../events/event_version_to_task_statuses.py | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index fdb48cbc37..6c4ebf2d10 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -1,12 +1,8 @@ from pype.modules.ftrack import BaseEvent -from pype.api import config +from pype.api import project_settings as get_project_settings class VersionToTaskStatus(BaseEvent): - - # Presets usage - default_status_mapping = {} - def launch(self, session, event): '''Propagates status from version to task when changed''' @@ -48,14 +44,20 @@ class VersionToTaskStatus(BaseEvent): version_status_orig = version_status["name"] + # Get entities necessary for processing + version = session.get("AssetVersion", entity["entityId"]) + task = version.get("task") + if not task: + continue + + project_entity = self.get_project_from_entity(task) + project_name = project_entity["full_name"] + project_settings = get_project_settings(project_name) + # Load status mapping from presets status_mapping = ( - config.get_presets() - .get("ftrack", {}) - .get("ftrack_config", {}) - .get("status_version_to_task") - ) or self.default_status_mapping - + project_settings["ftrack"]["event"]["status_version_to_task"] + ) # Skip if mapping is empty if not status_mapping: continue @@ -78,16 +80,10 @@ class VersionToTaskStatus(BaseEvent): # Lower all names from presets new_status_names = [name.lower() for name in new_status_names] - # Get entities necessary for processing - version = session.get("AssetVersion", entity["entityId"]) - task = version.get("task") - if not task: - continue - if version["asset"]["type"]["short"].lower() == "scene": continue - project_schema = task["project"]["project_schema"] + project_schema = project_entity["project_schema"] # Get all available statuses for Task statuses = project_schema.get_statuses("Task", task["type_id"]) # map lowered status name with it's object From ca7663bbc9f052c06da2d5346500d83b8472c2e8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 15:53:04 +0100 Subject: [PATCH 236/279] renamed overrides getter function --- pype/settings/lib.py | 12 ++++++------ pype/tools/settings/settings/widgets/base.py | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index 23e303556e..0856e7048a 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -288,7 +288,7 @@ def save_project_settings(project_name, overrides): Do not use to store whole project settings data with defaults but only it's overrides with metadata defining how overrides should be applied in load function. For loading should be used function - `get_studio_overrides_default_project_settings` for global project settings + `get_studio_project_settings_overrides` for global project settings and `get_project_settings_overrides` for project specific settings. Args: @@ -328,21 +328,21 @@ def save_project_anatomy(project_name, anatomy_data): json.dump(anatomy_data, file_stream, indent=4) -def get_studio_overrides_system_settings(): +def get_studio_system_settings_overrides(): """Studio overrides of system settings.""" if os.path.exists(SYSTEM_SETTINGS_PATH): return load_json_file(SYSTEM_SETTINGS_PATH) return {} -def get_studio_overrides_default_project_settings(): +def get_studio_project_settings_overrides(): """Studio overrides of default project settings.""" if os.path.exists(PROJECT_SETTINGS_PATH): return load_json_file(PROJECT_SETTINGS_PATH) return {} -def get_studio_overrides_default_project_anatomy(): +def get_studio_project_anatomy_overrides(): """Studio overrides of default project anatomy data.""" if os.path.exists(PROJECT_ANATOMY_PATH): return load_json_file(PROJECT_ANATOMY_PATH) @@ -416,14 +416,14 @@ def apply_overrides(source_data, override_data): def get_system_settings(): """System settings with applied studio overrides.""" default_values = get_default_settings()[SYSTEM_SETTINGS_KEY] - studio_values = get_studio_overrides_system_settings() + studio_values = get_studio_system_settings_overrides() return apply_overrides(default_values, studio_values) def get_default_project_settings(): """Project settings with applied studio's default project overrides.""" default_values = get_default_settings()[PROJECT_SETTINGS_KEY] - studio_values = get_studio_overrides_default_project_settings() + studio_values = get_studio_project_settings_overrides() return apply_overrides(default_values, studio_values) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index ec86da74c4..ae4d131265 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -12,8 +12,8 @@ from pype.settings.lib import ( reset_default_settings, get_default_settings, - get_studio_overrides_system_settings, - get_studio_overrides_default_project_settings, + get_studio_system_settings_overrides, + get_studio_project_settings_overrides, get_studio_overrides_default_project_anatomy, get_project_settings_overrides, @@ -384,7 +384,7 @@ class SystemWidget(SettingsCategoryWidget): system_values = lib.NOT_SET else: system_values = lib.convert_overrides_to_gui_data( - {self.main_schema_key: get_studio_overrides_system_settings()} + {self.main_schema_key: get_studio_system_settings_overrides()} ) for input_field in self.input_fields: @@ -610,7 +610,7 @@ class ProjectWidget(SettingsCategoryWidget): studio_values = lib.convert_overrides_to_gui_data({ self.main_schema_key: { PROJECT_SETTINGS_KEY: ( - get_studio_overrides_default_project_settings() + get_studio_project_settings_overrides() ), PROJECT_ANATOMY_KEY: ( get_studio_overrides_default_project_anatomy() From ab6482f61b64816b86b2f611a44017ad317d5aa6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 15:54:09 +0100 Subject: [PATCH 237/279] fix last functio name --- pype/tools/settings/settings/widgets/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index ae4d131265..5127ea9f88 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -14,7 +14,7 @@ from pype.settings.lib import ( get_studio_system_settings_overrides, get_studio_project_settings_overrides, - get_studio_overrides_default_project_anatomy, + get_studio_project_anatomy_overrides, get_project_settings_overrides, get_project_anatomy_overrides, @@ -613,7 +613,7 @@ class ProjectWidget(SettingsCategoryWidget): get_studio_project_settings_overrides() ), PROJECT_ANATOMY_KEY: ( - get_studio_overrides_default_project_anatomy() + get_studio_project_anatomy_overrides() ) } }) From 41ce3ea1905d92d7ca9a9d18e69382193a65006e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 15:57:43 +0100 Subject: [PATCH 238/279] last fix! --- pype/settings/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index 0856e7048a..33a427c3a6 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -431,7 +431,7 @@ def get_default_project_settings(): def get_default_project_anatomy_data(): """Project anatomy data with applied studio's default project overrides.""" default_values = get_default_settings()[PROJECT_ANATOMY_KEY] - studio_values = get_studio_overrides_default_project_anatomy() + studio_values = get_studio_project_anatomy_overrides() return apply_overrides(default_values, studio_values) From 92d751d94dfc6f4dfd7115fb2e358df380eecfa0 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 16:04:52 +0100 Subject: [PATCH 239/279] replace project_settings with get_project_settings --- .ropeproject/config.py | 114 ++++++++++++++++++ pype/__init__.py | 4 +- pype/lib/avalon_context.py | 4 +- pype/lib/plugin_tools.py | 4 +- .../action_create_project_structure.py | 6 +- .../ftrack/events/event_user_assigment.py | 6 +- .../events/event_version_to_task_statuses.py | 6 +- pype/plugin.py | 4 +- .../plugins/maya/create/create_rendersetup.py | 4 +- pype/plugins/maya/load/load_ass.py | 6 +- pype/plugins/maya/load/load_gpucache.py | 4 +- pype/plugins/maya/load/load_reference.py | 4 +- .../plugins/maya/load/load_vdb_to_redshift.py | 4 +- pype/plugins/maya/load/load_vdb_to_vray.py | 4 +- pype/plugins/maya/load/load_vrayproxy.py | 4 +- pype/plugins/maya/load/load_yeti_cache.py | 4 +- pype/plugins/maya/load/load_yeti_rig.py | 4 +- pype/plugins/nuke/load/load_mov.py | 4 +- pype/tools/pyblish_pype/control.py | 4 +- .../widgets/widget_family.py | 4 +- setup/maya/userSetup.py | 4 +- 21 files changed, 158 insertions(+), 44 deletions(-) create mode 100644 .ropeproject/config.py diff --git a/.ropeproject/config.py b/.ropeproject/config.py new file mode 100644 index 0000000000..dee2d1ae9a --- /dev/null +++ b/.ropeproject/config.py @@ -0,0 +1,114 @@ +# The default ``config.py`` +# flake8: noqa + + +def set_prefs(prefs): + """This function is called before opening the project""" + + # Specify which files and folders to ignore in the project. + # Changes to ignored resources are not added to the history and + # VCSs. Also they are not returned in `Project.get_files()`. + # Note that ``?`` and ``*`` match all characters but slashes. + # '*.pyc': matches 'test.pyc' and 'pkg/test.pyc' + # 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc' + # '.svn': matches 'pkg/.svn' and all of its children + # 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o' + # 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o' + prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject', + '.hg', '.svn', '_svn', '.git', '.tox'] + + # Specifies which files should be considered python files. It is + # useful when you have scripts inside your project. Only files + # ending with ``.py`` are considered to be python files by + # default. + # prefs['python_files'] = ['*.py'] + + # Custom source folders: By default rope searches the project + # for finding source folders (folders that should be searched + # for finding modules). You can add paths to that list. Note + # that rope guesses project source folders correctly most of the + # time; use this if you have any problems. + # The folders should be relative to project root and use '/' for + # separating folders regardless of the platform rope is running on. + # 'src/my_source_folder' for instance. + # prefs.add('source_folders', 'src') + + # You can extend python path for looking up modules + # prefs.add('python_path', '~/python/') + + # Should rope save object information or not. + prefs['save_objectdb'] = True + prefs['compress_objectdb'] = False + + # If `True`, rope analyzes each module when it is being saved. + prefs['automatic_soa'] = True + # The depth of calls to follow in static object analysis + prefs['soa_followed_calls'] = 0 + + # If `False` when running modules or unit tests "dynamic object + # analysis" is turned off. This makes them much faster. + prefs['perform_doa'] = True + + # Rope can check the validity of its object DB when running. + prefs['validate_objectdb'] = True + + # How many undos to hold? + prefs['max_history_items'] = 32 + + # Shows whether to save history across sessions. + prefs['save_history'] = True + prefs['compress_history'] = False + + # Set the number spaces used for indenting. According to + # :PEP:`8`, it is best to use 4 spaces. Since most of rope's + # unit-tests use 4 spaces it is more reliable, too. + prefs['indent_size'] = 4 + + # Builtin and c-extension modules that are allowed to be imported + # and inspected by rope. + prefs['extension_modules'] = [] + + # Add all standard c-extensions to extension_modules list. + prefs['import_dynload_stdmods'] = True + + # If `True` modules with syntax errors are considered to be empty. + # The default value is `False`; When `False` syntax errors raise + # `rope.base.exceptions.ModuleSyntaxError` exception. + prefs['ignore_syntax_errors'] = False + + # If `True`, rope ignores unresolvable imports. Otherwise, they + # appear in the importing namespace. + prefs['ignore_bad_imports'] = False + + # If `True`, rope will insert new module imports as + # `from import ` by default. + prefs['prefer_module_from_imports'] = False + + # If `True`, rope will transform a comma list of imports into + # multiple separate import statements when organizing + # imports. + prefs['split_imports'] = False + + # If `True`, rope will remove all top-level import statements and + # reinsert them at the top of the module when making changes. + prefs['pull_imports_to_top'] = True + + # If `True`, rope will sort imports alphabetically by module name instead + # of alphabetically by import statement, with from imports after normal + # imports. + prefs['sort_imports_alphabetically'] = False + + # Location of implementation of + # rope.base.oi.type_hinting.interfaces.ITypeHintingFactory In general + # case, you don't have to change this value, unless you're an rope expert. + # Change this value to inject you own implementations of interfaces + # listed in module rope.base.oi.type_hinting.providers.interfaces + # For example, you can add you own providers for Django Models, or disable + # the search type-hinting in a class hierarchy, etc. + prefs['type_hinting_factory'] = ( + 'rope.base.oi.type_hinting.factory.default_type_hinting_factory') + + +def project_opened(project): + """This function is called after opening the project""" + # Do whatever you like here! diff --git a/pype/__init__.py b/pype/__init__.py index 928bff6e9d..8481fa2d48 100644 --- a/pype/__init__.py +++ b/pype/__init__.py @@ -2,7 +2,7 @@ import os from pyblish import api as pyblish from avalon import api as avalon -from .api import project_settings, Anatomy +from .api import get_project_settings, Anatomy from .lib import filter_pyblish_plugins @@ -50,7 +50,7 @@ def patched_discover(superclass): print(">>> trying to find presets for {}:{} ...".format(host, plugin_type)) try: - settings = project_settings(os.environ['AVALON_PROJECT'])[host][plugin_type] + settings = get_project_settings(os.environ['AVALON_PROJECT'])[host][plugin_type] except KeyError: print("*** no presets found.") else: diff --git a/pype/lib/avalon_context.py b/pype/lib/avalon_context.py index c984e47b91..25966d550e 100644 --- a/pype/lib/avalon_context.py +++ b/pype/lib/avalon_context.py @@ -5,7 +5,7 @@ import logging import collections from avalon import io, pipeline -from ..api import project_settings +from ..api import get_project_settings import avalon.api log = logging.getLogger("AvalonContext") @@ -410,7 +410,7 @@ class BuildWorkfile: (dict): preset per entered task name """ host_name = avalon.api.registered_host().__name__.rsplit(".", 1)[-1] - presets = project_settings(io.Session["AVALON_PROJECT"]) + presets = get_project_settings(io.Session["AVALON_PROJECT"]) # Get presets for host build_presets = ( presets.get(host_name, {}) diff --git a/pype/lib/plugin_tools.py b/pype/lib/plugin_tools.py index 185ebce10f..726726bb4c 100644 --- a/pype/lib/plugin_tools.py +++ b/pype/lib/plugin_tools.py @@ -4,7 +4,7 @@ import os import inspect import logging -from ..api import config, project_settings +from ..api import config, get_project_settings log = logging.getLogger(__name__) @@ -25,7 +25,7 @@ def filter_pyblish_plugins(plugins): host = api.current_host() - presets = project_settings(os.environ['AVALON_PROJECT']) or {} + presets = get_project_settings(os.environ['AVALON_PROJECT']) or {} # iterate over plugins for plugin in plugins[:]: diff --git a/pype/modules/ftrack/actions/action_create_project_structure.py b/pype/modules/ftrack/actions/action_create_project_structure.py index d5cb381a63..4fc59da89e 100644 --- a/pype/modules/ftrack/actions/action_create_project_structure.py +++ b/pype/modules/ftrack/actions/action_create_project_structure.py @@ -2,7 +2,7 @@ import os import re from pype.modules.ftrack.lib import BaseAction, statics_icon -from pype.api import Anatomy, project_settings as get_project_settings +from pype.api import Anatomy, get_project_settings as get_project_settings class CreateProjectFolders(BaseAction): @@ -73,9 +73,9 @@ class CreateProjectFolders(BaseAction): project_entity = self.get_project_from_entity(entities[0]) # Load settings for project project_name = project_entity["full_name"] - project_settings = get_project_settings(project_name) + get_project_settings = get_project_settings(project_name) project_folder_structure = ( - project_settings["global"]["project_folder_structure"] + get_project_settings["global"]["project_folder_structure"] ) if not project_folder_structure: return { diff --git a/pype/modules/ftrack/events/event_user_assigment.py b/pype/modules/ftrack/events/event_user_assigment.py index bc05faa192..6a230f6ff9 100644 --- a/pype/modules/ftrack/events/event_user_assigment.py +++ b/pype/modules/ftrack/events/event_user_assigment.py @@ -8,7 +8,7 @@ from avalon.api import AvalonMongoDB from bson.objectid import ObjectId -from pype.api import Anatomy, project_settings as get_project_settings +from pype.api import Anatomy, get_project_settings as get_project_settings class UserAssigmentEvent(BaseEvent): @@ -200,9 +200,9 @@ class UserAssigmentEvent(BaseEvent): project_name = task_entity["project"]["full_name"] project_data = tmp_by_project_name.get(project_name) or {} if "scripts_by_action" not in project_data: - project_settings = get_project_settings(project_name) + get_project_settings = get_project_settings(project_name) _settings = ( - project_settings["ftrack"]["events"]["user_assignment"] + get_project_settings["ftrack"]["events"]["user_assignment"] ) project_data["scripts_by_action"] = _settings.get("scripts") tmp_by_project_name[project_name] = project_data diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index 6c4ebf2d10..ca55f24f32 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -1,5 +1,5 @@ from pype.modules.ftrack import BaseEvent -from pype.api import project_settings as get_project_settings +from pype.api import get_project_settings as get_project_settings class VersionToTaskStatus(BaseEvent): @@ -52,11 +52,11 @@ class VersionToTaskStatus(BaseEvent): project_entity = self.get_project_from_entity(task) project_name = project_entity["full_name"] - project_settings = get_project_settings(project_name) + get_project_settings = get_project_settings(project_name) # Load status mapping from presets status_mapping = ( - project_settings["ftrack"]["event"]["status_version_to_task"] + get_project_settings["ftrack"]["event"]["status_version_to_task"] ) # Skip if mapping is empty if not status_mapping: diff --git a/pype/plugin.py b/pype/plugin.py index 8d53e9c4be..1b769cd1f1 100644 --- a/pype/plugin.py +++ b/pype/plugin.py @@ -2,7 +2,7 @@ import tempfile import os import pyblish.api -from pype.api import project_settings +from pype.api import get_project_settings import inspect ValidatePipelineOrder = pyblish.api.ValidatorOrder + 0.05 @@ -24,7 +24,7 @@ def imprint_attributes(plugin): plugin_host = file.split(os.path.sep)[-3:-2][0] plugin_name = type(plugin).__name__ try: - settings = project_settings(os.environ['AVALON_PROJECT']) + settings = get_project_settings(os.environ['AVALON_PROJECT']) settings_data = settings[plugin_host][plugin_kind][plugin_name] # noqa: E501 print(settings_data) except KeyError: diff --git a/pype/plugins/maya/create/create_rendersetup.py b/pype/plugins/maya/create/create_rendersetup.py index 406d90223f..969c085ea6 100644 --- a/pype/plugins/maya/create/create_rendersetup.py +++ b/pype/plugins/maya/create/create_rendersetup.py @@ -26,9 +26,9 @@ class CreateRenderSetup(avalon.maya.Creator): # \__| | # \_____/ - # from pype.api import project_settings + # from pype.api import get_project_settings # import maya.app.renderSetup.model.renderSetup as renderSetup - # settings = project_settings(os.environ['AVALON_PROJECT']) + # settings = get_project_settings(os.environ['AVALON_PROJECT']) # layer = settings['maya']['create']['renderSetup']["layer"] # rs = renderSetup.instance() diff --git a/pype/plugins/maya/load/load_ass.py b/pype/plugins/maya/load/load_ass.py index dc3e0043ee..9b851a3757 100644 --- a/pype/plugins/maya/load/load_ass.py +++ b/pype/plugins/maya/load/load_ass.py @@ -1,7 +1,7 @@ from avalon import api import pype.hosts.maya.plugin import os -from pype.api import project_settings +from pype.api import get_project_settings import clique @@ -74,7 +74,7 @@ class AssProxyLoader(pype.hosts.maya.plugin.ReferenceLoader): proxyShape.dso.set(path) proxyShape.aiOverrideShaders.set(0) - settings = project_settings(os.environ['AVALON_PROJECT']) + settings = get_project_settings(os.environ['AVALON_PROJECT']) colors = settings['maya']['load']['colors'] c = colors.get(family) @@ -196,7 +196,7 @@ class AssStandinLoader(api.Loader): label = "{}:{}".format(namespace, name) root = pm.group(name=label, empty=True) - settings = project_settings(os.environ['AVALON_PROJECT']) + settings = get_project_settings(os.environ['AVALON_PROJECT']) colors = settings['maya']['load']['colors'] c = colors.get('ass') diff --git a/pype/plugins/maya/load/load_gpucache.py b/pype/plugins/maya/load/load_gpucache.py index 6520be0a07..0b3daae710 100644 --- a/pype/plugins/maya/load/load_gpucache.py +++ b/pype/plugins/maya/load/load_gpucache.py @@ -1,7 +1,7 @@ from avalon import api import pype.hosts.maya.plugin import os -from pype.api import project_settings +from pype.api import get_project_settings reload(config) @@ -35,7 +35,7 @@ class GpuCacheLoader(api.Loader): label = "{}:{}".format(namespace, name) root = cmds.group(name=label, empty=True) - settings = project_settings(os.environ['AVALON_PROJECT']) + settings = get_project_settings(os.environ['AVALON_PROJECT']) colors = settings['maya']['load']['colors'] c = colors.get('model') if c is not None: diff --git a/pype/plugins/maya/load/load_reference.py b/pype/plugins/maya/load/load_reference.py index 90a3015894..23b3cedb55 100644 --- a/pype/plugins/maya/load/load_reference.py +++ b/pype/plugins/maya/load/load_reference.py @@ -2,7 +2,7 @@ import pype.hosts.maya.plugin from avalon import api, maya from maya import cmds import os -from pype.api import project_settings +from pype.api import get_project_settings class ReferenceLoader(pype.hosts.maya.plugin.ReferenceLoader): @@ -77,7 +77,7 @@ class ReferenceLoader(pype.hosts.maya.plugin.ReferenceLoader): cmds.setAttr(groupName + ".displayHandle", 1) - settings = project_settings(os.environ['AVALON_PROJECT']) + settings = get_project_settings(os.environ['AVALON_PROJECT']) colors = settings['maya']['load']['colors'] c = colors.get(family) if c is not None: diff --git a/pype/plugins/maya/load/load_vdb_to_redshift.py b/pype/plugins/maya/load/load_vdb_to_redshift.py index 885f0f23c8..17c78d7165 100644 --- a/pype/plugins/maya/load/load_vdb_to_redshift.py +++ b/pype/plugins/maya/load/load_vdb_to_redshift.py @@ -1,6 +1,6 @@ from avalon import api import os -from pype.api import project_settings +from pype.api import get_project_settings class LoadVDBtoRedShift(api.Loader): """Load OpenVDB in a Redshift Volume Shape""" @@ -55,7 +55,7 @@ class LoadVDBtoRedShift(api.Loader): label = "{}:{}".format(namespace, name) root = cmds.group(name=label, empty=True) - settings = project_settings(os.environ['AVALON_PROJECT']) + settings = get_project_settings(os.environ['AVALON_PROJECT']) colors = settings['maya']['load']['colors'] c = colors.get(family) diff --git a/pype/plugins/maya/load/load_vdb_to_vray.py b/pype/plugins/maya/load/load_vdb_to_vray.py index 9bfdda0308..2959ef42ec 100644 --- a/pype/plugins/maya/load/load_vdb_to_vray.py +++ b/pype/plugins/maya/load/load_vdb_to_vray.py @@ -1,5 +1,5 @@ from avalon import api -from pype.api import project_settings +from pype.api import get_project_settings import os @@ -48,7 +48,7 @@ class LoadVDBtoVRay(api.Loader): label = "{}:{}".format(namespace, name) root = cmds.group(name=label, empty=True) - settings = project_settings(os.environ['AVALON_PROJECT']) + settings = get_project_settings(os.environ['AVALON_PROJECT']) colors = settings['maya']['load']['colors'] c = colors.get(family) diff --git a/pype/plugins/maya/load/load_vrayproxy.py b/pype/plugins/maya/load/load_vrayproxy.py index 1294df2fc7..73f02b81e4 100644 --- a/pype/plugins/maya/load/load_vrayproxy.py +++ b/pype/plugins/maya/load/load_vrayproxy.py @@ -1,6 +1,6 @@ from avalon.maya import lib from avalon import api -from pype.api import project_settings +from pype.api import get_project_settings import os import maya.cmds as cmds @@ -47,7 +47,7 @@ class VRayProxyLoader(api.Loader): return # colour the group node - settings = project_settings(os.environ['AVALON_PROJECT']) + settings = get_project_settings(os.environ['AVALON_PROJECT']) colors = settings['maya']['load']['colors'] c = colors.get(family) if c is not None: diff --git a/pype/plugins/maya/load/load_yeti_cache.py b/pype/plugins/maya/load/load_yeti_cache.py index 8ee1602202..19cf3920fe 100644 --- a/pype/plugins/maya/load/load_yeti_cache.py +++ b/pype/plugins/maya/load/load_yeti_cache.py @@ -9,7 +9,7 @@ from maya import cmds from avalon import api, io from avalon.maya import lib as avalon_lib, pipeline from pype.hosts.maya import lib -from pype.api import project_settings +from pype.api import get_project_settings from pprint import pprint @@ -59,7 +59,7 @@ class YetiCacheLoader(api.Loader): group_name = "{}:{}".format(namespace, name) group_node = cmds.group(nodes, name=group_name) - settings = project_settings(os.environ['AVALON_PROJECT']) + settings = get_project_settings(os.environ['AVALON_PROJECT']) colors = settings['maya']['load']['colors'] c = colors.get(family) diff --git a/pype/plugins/maya/load/load_yeti_rig.py b/pype/plugins/maya/load/load_yeti_rig.py index bd74fcbc43..3a9339c707 100644 --- a/pype/plugins/maya/load/load_yeti_rig.py +++ b/pype/plugins/maya/load/load_yeti_rig.py @@ -1,7 +1,7 @@ import os from collections import defaultdict -from pype.api import project_settings +from pype.api import get_project_settings import pype.hosts.maya.plugin from pype.hosts.maya import lib @@ -77,7 +77,7 @@ class YetiRigLoader(pype.hosts.maya.plugin.ReferenceLoader): groupName = "{}:{}".format(namespace, name) - settings = project_settings(os.environ['AVALON_PROJECT']) + settings = get_project_settings(os.environ['AVALON_PROJECT']) colors = settings['maya']['load']['colors'] c = colors.get('yetiRig') diff --git a/pype/plugins/nuke/load/load_mov.py b/pype/plugins/nuke/load/load_mov.py index 078127ee42..104f59d5be 100644 --- a/pype/plugins/nuke/load/load_mov.py +++ b/pype/plugins/nuke/load/load_mov.py @@ -4,7 +4,7 @@ import contextlib from avalon import api, io from pype.hosts.nuke import presets -from pype.api import project_settings +from pype.api import get_project_settings @contextlib.contextmanager @@ -73,7 +73,7 @@ def add_review_presets_config(): "families": list(), "representations": list() } - settings = project_settings(io.Session["AVALON_PROJECT"]) + settings = get_project_settings(io.Session["AVALON_PROJECT"]) review_presets = settings["global"]["publish"].get( "ExtractReview", {}) diff --git a/pype/tools/pyblish_pype/control.py b/pype/tools/pyblish_pype/control.py index 0994e25d4a..4f7a43d6d1 100644 --- a/pype/tools/pyblish_pype/control.py +++ b/pype/tools/pyblish_pype/control.py @@ -22,7 +22,7 @@ import pyblish.version from . import util from .constants import InstanceStates -from pype.api import project_settings +from pype.api import get_project_settings class IterationBreak(Exception): @@ -121,7 +121,7 @@ class Controller(QtCore.QObject): def presets_by_hosts(self): # Get global filters as base - presets = project_settings(os.environ['AVALON_PROJECT']) or {} + presets = get_project_settings(os.environ['AVALON_PROJECT']) or {} if not presets: return {} diff --git a/pype/tools/standalonepublish/widgets/widget_family.py b/pype/tools/standalonepublish/widgets/widget_family.py index be68e411fd..5c0c8ccd38 100644 --- a/pype/tools/standalonepublish/widgets/widget_family.py +++ b/pype/tools/standalonepublish/widgets/widget_family.py @@ -5,7 +5,7 @@ from Qt import QtWidgets, QtCore from . import HelpRole, FamilyRole, ExistsRole, PluginRole, PluginKeyRole from . import FamilyDescriptionWidget -from pype.api import project_settings +from pype.api import get_project_settings class FamilyWidget(QtWidgets.QWidget): @@ -310,7 +310,7 @@ class FamilyWidget(QtWidgets.QWidget): def refresh(self): has_families = False - settings = project_settings(os.environ['AVALON_PROJECT']) + settings = get_project_settings(os.environ['AVALON_PROJECT']) sp_settings = settings.get('standalonepublisher', {}) print(sp_settings) diff --git a/setup/maya/userSetup.py b/setup/maya/userSetup.py index 3cf2718796..e401580bd8 100644 --- a/setup/maya/userSetup.py +++ b/setup/maya/userSetup.py @@ -1,5 +1,5 @@ import os -from pype.api import project_settings +from pype.api import get_project_settings import pype.hosts.maya.lib as mlib from maya import cmds @@ -7,7 +7,7 @@ from maya import cmds print("starting PYPE usersetup") # build a shelf -settings = project_settings(os.environ['AVALON_PROJECT']) +settings = get_project_settings(os.environ['AVALON_PROJECT']) shelf_preset = settings['maya'].get('project_shelf') From fccdd586be866cc27a2ca6a6abcbee4870dce6b1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 16:08:20 +0100 Subject: [PATCH 240/279] remove .ropeproject --- .gitignore | 2 + .ropeproject/config.py | 114 ----------------------------------------- 2 files changed, 2 insertions(+), 114 deletions(-) delete mode 100644 .ropeproject/config.py diff --git a/.gitignore b/.gitignore index 101c1e6224..044efb4617 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,8 @@ __pycache__/ Icon # Thumbnails ._* +# rope project dir +.ropeproject # Files that might appear in the root of a volume .DocumentRevisions-V100 .fseventsd diff --git a/.ropeproject/config.py b/.ropeproject/config.py deleted file mode 100644 index dee2d1ae9a..0000000000 --- a/.ropeproject/config.py +++ /dev/null @@ -1,114 +0,0 @@ -# The default ``config.py`` -# flake8: noqa - - -def set_prefs(prefs): - """This function is called before opening the project""" - - # Specify which files and folders to ignore in the project. - # Changes to ignored resources are not added to the history and - # VCSs. Also they are not returned in `Project.get_files()`. - # Note that ``?`` and ``*`` match all characters but slashes. - # '*.pyc': matches 'test.pyc' and 'pkg/test.pyc' - # 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc' - # '.svn': matches 'pkg/.svn' and all of its children - # 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o' - # 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o' - prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject', - '.hg', '.svn', '_svn', '.git', '.tox'] - - # Specifies which files should be considered python files. It is - # useful when you have scripts inside your project. Only files - # ending with ``.py`` are considered to be python files by - # default. - # prefs['python_files'] = ['*.py'] - - # Custom source folders: By default rope searches the project - # for finding source folders (folders that should be searched - # for finding modules). You can add paths to that list. Note - # that rope guesses project source folders correctly most of the - # time; use this if you have any problems. - # The folders should be relative to project root and use '/' for - # separating folders regardless of the platform rope is running on. - # 'src/my_source_folder' for instance. - # prefs.add('source_folders', 'src') - - # You can extend python path for looking up modules - # prefs.add('python_path', '~/python/') - - # Should rope save object information or not. - prefs['save_objectdb'] = True - prefs['compress_objectdb'] = False - - # If `True`, rope analyzes each module when it is being saved. - prefs['automatic_soa'] = True - # The depth of calls to follow in static object analysis - prefs['soa_followed_calls'] = 0 - - # If `False` when running modules or unit tests "dynamic object - # analysis" is turned off. This makes them much faster. - prefs['perform_doa'] = True - - # Rope can check the validity of its object DB when running. - prefs['validate_objectdb'] = True - - # How many undos to hold? - prefs['max_history_items'] = 32 - - # Shows whether to save history across sessions. - prefs['save_history'] = True - prefs['compress_history'] = False - - # Set the number spaces used for indenting. According to - # :PEP:`8`, it is best to use 4 spaces. Since most of rope's - # unit-tests use 4 spaces it is more reliable, too. - prefs['indent_size'] = 4 - - # Builtin and c-extension modules that are allowed to be imported - # and inspected by rope. - prefs['extension_modules'] = [] - - # Add all standard c-extensions to extension_modules list. - prefs['import_dynload_stdmods'] = True - - # If `True` modules with syntax errors are considered to be empty. - # The default value is `False`; When `False` syntax errors raise - # `rope.base.exceptions.ModuleSyntaxError` exception. - prefs['ignore_syntax_errors'] = False - - # If `True`, rope ignores unresolvable imports. Otherwise, they - # appear in the importing namespace. - prefs['ignore_bad_imports'] = False - - # If `True`, rope will insert new module imports as - # `from import ` by default. - prefs['prefer_module_from_imports'] = False - - # If `True`, rope will transform a comma list of imports into - # multiple separate import statements when organizing - # imports. - prefs['split_imports'] = False - - # If `True`, rope will remove all top-level import statements and - # reinsert them at the top of the module when making changes. - prefs['pull_imports_to_top'] = True - - # If `True`, rope will sort imports alphabetically by module name instead - # of alphabetically by import statement, with from imports after normal - # imports. - prefs['sort_imports_alphabetically'] = False - - # Location of implementation of - # rope.base.oi.type_hinting.interfaces.ITypeHintingFactory In general - # case, you don't have to change this value, unless you're an rope expert. - # Change this value to inject you own implementations of interfaces - # listed in module rope.base.oi.type_hinting.providers.interfaces - # For example, you can add you own providers for Django Models, or disable - # the search type-hinting in a class hierarchy, etc. - prefs['type_hinting_factory'] = ( - 'rope.base.oi.type_hinting.factory.default_type_hinting_factory') - - -def project_opened(project): - """This function is called after opening the project""" - # Do whatever you like here! From c64fdd19ddb17f6c9a7b778df65f25357c25522c Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 16:08:50 +0100 Subject: [PATCH 241/279] system_settings to get_system_settings --- pype/lib/applications.py | 2 +- pype/plugins/maya/publish/submit_maya_muster.py | 4 ++-- pype/tools/pyblish_pype/model.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pype/lib/applications.py b/pype/lib/applications.py index 9b6e364a4c..bee51d0570 100644 --- a/pype/lib/applications.py +++ b/pype/lib/applications.py @@ -8,7 +8,7 @@ from abc import ABCMeta, abstractmethod import six -from pype.settings import system_settings, environments +from pype.settings import get_system_settings, get_environments from ..api import Logger from .python_module_tools import ( diff --git a/pype/plugins/maya/publish/submit_maya_muster.py b/pype/plugins/maya/publish/submit_maya_muster.py index df75fce1a4..65889bf068 100644 --- a/pype/plugins/maya/publish/submit_maya_muster.py +++ b/pype/plugins/maya/publish/submit_maya_muster.py @@ -11,7 +11,7 @@ from avalon.vendor import requests import pyblish.api from pype.hosts.maya import lib -from pype.api import system_settings +from pype.api import get_system_settings # mapping between Maya renderer names and Muster template ids @@ -25,7 +25,7 @@ def _get_template_id(renderer): :rtype: int """ - templates = system_settings()["modules"]["Muster"]["templates_mapping"] + templates = get_system_settings()["modules"]["Muster"]["templates_mapping"] if not templates: raise RuntimeError(("Muster template mapping missing in pype-settings")) try: diff --git a/pype/tools/pyblish_pype/model.py b/pype/tools/pyblish_pype/model.py index 8c9bc07d7e..88dce679f7 100644 --- a/pype/tools/pyblish_pype/model.py +++ b/pype/tools/pyblish_pype/model.py @@ -35,7 +35,7 @@ from six import text_type from .vendor import qtawesome from .constants import PluginStates, InstanceStates, GroupStates, Roles -from pype.api import system_settings +from pype.api import get_system_settings # ItemTypes @@ -104,7 +104,7 @@ class IntentModel(QtGui.QStandardItemModel): self.default_index = 0 intents_preset = ( - system_settings() + get_system_settings() .get("modules", {}) .get("Ftrack", {}) .get("intent", {}) From 9e407af9d3bb442a5af40537a5094464211a681b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 16:27:07 +0100 Subject: [PATCH 242/279] empty dictionary is passed to ftrack events and actions instead of presets --- pype/modules/ftrack/ftrack_server/ftrack_server.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pype/modules/ftrack/ftrack_server/ftrack_server.py b/pype/modules/ftrack/ftrack_server/ftrack_server.py index 9940ab236e..ec39bdc50f 100644 --- a/pype/modules/ftrack/ftrack_server/ftrack_server.py +++ b/pype/modules/ftrack/ftrack_server/ftrack_server.py @@ -8,7 +8,7 @@ import inspect import ftrack_api -from pype.api import Logger, config +from pype.api import Logger log = Logger().get_logger(__name__) @@ -111,9 +111,8 @@ class FtrackServer: key = "user" if self.server_type.lower() == "event": key = "server" - plugins_presets = config.get_presets().get( - "ftrack", {} - ).get("plugins", {}).get(key, {}) + # TODO replace with settings or get rid of passing the dictionary + plugins_presets = {} function_counter = 0 for function_dict in register_functions_dict: From d7af09160cbffdf742874dfb2d30f90c24310c5c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 16:28:23 +0100 Subject: [PATCH 243/279] rv action is just checking for rv path and do not use presets --- pype/modules/ftrack/actions/action_rv.py | 30 ++++++++++-------------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/pype/modules/ftrack/actions/action_rv.py b/pype/modules/ftrack/actions/action_rv.py index f9aeb87f71..eeb5672047 100644 --- a/pype/modules/ftrack/actions/action_rv.py +++ b/pype/modules/ftrack/actions/action_rv.py @@ -3,7 +3,6 @@ import subprocess import traceback import json -from pype.api import config from pype.modules.ftrack.lib import BaseAction, statics_icon import ftrack_api from avalon import io, api @@ -11,7 +10,6 @@ from avalon import io, api class RVAction(BaseAction): """ Launch RV action """ - ignore_me = "rv" not in config.get_presets() identifier = "rv.launch.action" label = "rv" description = "rv Launcher" @@ -19,6 +17,8 @@ class RVAction(BaseAction): type = 'Application' + allowed_types = ["img", "mov", "exr", "mp4"] + def __init__(self, session, plugins_presets): """ Constructor @@ -26,36 +26,30 @@ class RVAction(BaseAction): :type session: :class:`ftrack_api.Session` """ super().__init__(session, plugins_presets) - self.rv_path = None - self.config_data = None + + # QUESTION load RV application data from AppplicationManager? + rv_path = None # RV_HOME should be set if properly installed if os.environ.get('RV_HOME'): - self.rv_path = os.path.join( + rv_path = os.path.join( os.environ.get('RV_HOME'), 'bin', 'rv' ) - else: - # if not, fallback to config file location - if "rv" in config.get_presets(): - self.config_data = config.get_presets()['rv']['config'] - self.set_rv_path() + if not os.path.exists(rv_path): + rv_path = None - if self.rv_path is None: - return + if not rv_path: + self.log.info("RV path was not found.") + self.ignore_me = True - self.allowed_types = self.config_data.get( - 'file_ext', ["img", "mov", "exr", "mp4"] - ) + self.rv_path = rv_path def discover(self, session, entities, event): """Return available actions based on *event*. """ return True - def set_rv_path(self): - self.rv_path = self.config_data.get("rv_path") - def preregister(self): if self.rv_path is None: return ( From a633307b2d72e634f924e0f98e971454d397c06a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 16:33:42 +0100 Subject: [PATCH 244/279] added default roles for project cusstom attributes --- .../defaults/system_settings/modules.json | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/pype/settings/defaults/system_settings/modules.json b/pype/settings/defaults/system_settings/modules.json index 8c228e91ef..4a91d2dddf 100644 --- a/pype/settings/defaults/system_settings/modules.json +++ b/pype/settings/defaults/system_settings/modules.json @@ -58,13 +58,25 @@ "show": { "avalon_auto_sync": { "default": "", - "write_security_role": [], - "read_security_role": [] + "write_security_role": [ + "API", + "Administrator" + ], + "read_security_role": [ + "API", + "Administrator" + ] }, "library_project": { "default": "", - "write_security_role": [], - "read_security_role": [] + "write_security_role": [ + "API", + "Administrator" + ], + "read_security_role": [ + "API", + "Administrator" + ] } }, "is_hierarchical": { @@ -190,4 +202,4 @@ "Idle Manager": { "enabled": true } -} \ No newline at end of file +} From d5b10b085ea782d3179b2e9e7c40c340563a63e6 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 16:51:39 +0100 Subject: [PATCH 245/279] load nuke creator from settings --- pype/hosts/nuke/plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/hosts/nuke/plugin.py b/pype/hosts/nuke/plugin.py index 652c0396a8..5d00b19ec5 100644 --- a/pype/hosts/nuke/plugin.py +++ b/pype/hosts/nuke/plugin.py @@ -1,13 +1,13 @@ import re import avalon.api import avalon.nuke -from pype.api import config +from pype.api import get_current_project_settings class PypeCreator(avalon.nuke.pipeline.Creator): """Pype Nuke Creator class wrapper """ def __init__(self, *args, **kwargs): super(PypeCreator, self).__init__(*args, **kwargs) - self.presets = config.get_presets()['plugins']["nuke"]["create"].get( + self.presets = get_current_project_settings()["nuke"]["create"].get( self.__class__.__name__, {} ) From 06d9f9ab5250c0f2e2e151cfab98185c37307222 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 16:56:47 +0100 Subject: [PATCH 246/279] create update custom attributes use settings --- .../actions/action_create_cust_attrs.py | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/pype/modules/ftrack/actions/action_create_cust_attrs.py b/pype/modules/ftrack/actions/action_create_cust_attrs.py index f76d794d6f..68fae16382 100644 --- a/pype/modules/ftrack/actions/action_create_cust_attrs.py +++ b/pype/modules/ftrack/actions/action_create_cust_attrs.py @@ -1,6 +1,4 @@ -import os import collections -import toml import json import arrow import ftrack_api @@ -8,7 +6,7 @@ from pype.modules.ftrack.lib import BaseAction, statics_icon from pype.modules.ftrack.lib.avalon_sync import ( CUST_ATTR_ID_KEY, CUST_ATTR_GROUP, default_custom_attributes_definition ) -from pype.api import config +from pype.api import get_system_settings from pype.lib import ApplicationManager """ @@ -213,15 +211,12 @@ class CustomAttributes(BaseAction): self.groups = {} - self.presets = config.get_presets() + self.ftrack_settings = get_system_settings()["modules"]["Ftrack"] self.attrs_presets = self.prepare_attribute_pressets() def prepare_attribute_pressets(self): output = {} - - attr_presets = ( - self.presets.get("ftrack", {}).get("ftrack_custom_attributes") - ) or {} + attr_presets = self.ftrack_settings["custom_attributes"] for entity_type, preset in attr_presets.items(): # Lower entity type entity_type = entity_type.lower() @@ -429,12 +424,7 @@ class CustomAttributes(BaseAction): self.process_attr_data(tools_custom_attr_data, event) def intent_attribute(self, event): - intent_key_values = ( - self.presets - .get("global", {}) - .get("intent", {}) - .get("items", {}) - ) or {} + intent_key_values = self.ftrack_settings["intent"]["items"] intent_values = [] for key, label in intent_key_values.items(): @@ -740,6 +730,9 @@ class CustomAttributes(BaseAction): return default err_msg = 'Default value is not' if type == 'number': + if isinstance(default, (str)) and default.isnumeric(): + default = float(default) + if not isinstance(default, (float, int)): raise CustAttrException('{} integer'.format(err_msg)) elif type == 'text': From 1838f70ae090259e6b7be85a709de84ea6598e04 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 17:03:49 +0100 Subject: [PATCH 247/279] harmony read from settings --- pype/hosts/harmony/__init__.py | 6 ++-- .../defaults/project_settings/harmony.json | 7 ++++ .../schema_project_harmony.json | 34 +++++++++++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 pype/settings/defaults/project_settings/harmony.json create mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_harmony.json diff --git a/pype/hosts/harmony/__init__.py b/pype/hosts/harmony/__init__.py index 7ea261292e..bc91b4db2f 100644 --- a/pype/hosts/harmony/__init__.py +++ b/pype/hosts/harmony/__init__.py @@ -9,7 +9,7 @@ import avalon.tools.sceneinventory import pyblish.api from pype import lib -from pype.api import config +from pype.api import get_current_project_settings def set_scene_settings(settings): @@ -51,9 +51,9 @@ def get_asset_settings(): try: skip_resolution_check = \ - config.get_presets()["harmony"]["general"]["skip_resolution_check"] + get_current_project_settings()["harmony"]["general"]["skip_resolution_check"] skip_timelines_check = \ - config.get_presets()["harmony"]["general"]["skip_timelines_check"] + get_current_project_settings()["harmony"]["general"]["skip_timelines_check"] except KeyError: skip_resolution_check = [] skip_timelines_check = [] diff --git a/pype/settings/defaults/project_settings/harmony.json b/pype/settings/defaults/project_settings/harmony.json new file mode 100644 index 0000000000..5eca4f60eb --- /dev/null +++ b/pype/settings/defaults/project_settings/harmony.json @@ -0,0 +1,7 @@ +{ + "publish": {}, + "general": { + "skip_resolution_check": false, + "skip_timelines_check": false + } +} \ No newline at end of file diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_harmony.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_harmony.json new file mode 100644 index 0000000000..282a4350b6 --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_harmony.json @@ -0,0 +1,34 @@ +{ + "type": "dict", + "collapsable": true, + "key": "harmony", + "label": "Harmony", + "is_file": true, + "children": [ + { + "type": "dict", + "collapsable": true, + "key": "publish", + "label": "Publish plugins", + "children": [] + }, + { + "type": "dict", + "collapsable": true, + "key": "general", + "label": "General", + "children": [ + + { + "type": "boolean", + "key": "skip_resolution_check", + "label": "Skip Resolution Check" + }, + { + "type": "boolean", + "key": "skip_timelines_check", + "label": "Skip Timeliene Check" + } + ] + }] +} From be5eaa6701ab00dc4908d5723db2b040a6336b32 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 17:05:02 +0100 Subject: [PATCH 248/279] add harmony and minor cosmetics --- .../defaults/project_settings/ftrack.json | 2 +- .../defaults/project_settings/maya.json | 91 +++++++++++++++---- .../project_settings/standalonepublisher.json | 6 +- .../projects_schema/schema_main.json | 6 +- 4 files changed, 82 insertions(+), 23 deletions(-) diff --git a/pype/settings/defaults/project_settings/ftrack.json b/pype/settings/defaults/project_settings/ftrack.json index 4eabb52dc1..023b85cb3b 100644 --- a/pype/settings/defaults/project_settings/ftrack.json +++ b/pype/settings/defaults/project_settings/ftrack.json @@ -95,4 +95,4 @@ "note_labels": [] } } -} +} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/maya.json b/pype/settings/defaults/project_settings/maya.json index 0c640a63e4..9193ea2b52 100644 --- a/pype/settings/defaults/project_settings/maya.json +++ b/pype/settings/defaults/project_settings/maya.json @@ -132,7 +132,7 @@ "regex": "" }, "ValidateMeshHasOverlappingUVs": { - "enabled": true + "enabled": false }, "ExtractCameraAlembic": { "enabled": true, @@ -145,23 +145,78 @@ } }, "load": { - "colors": { - "model": [0.821, 0.518, 0.117], - "rig": [0.144, 0.443, 0.463], - "pointcache": [0.368, 0.821, 0.117], - "animation": [0.368, 0.821, 0.117], - "ass": [1.0, 0.332, 0.312], - "camera": [0.447, 0.312, 1.0], - "camerarig": [0.447, 0.312, 1.0], - "fbx": [1.0, 0.931, 0.312], - "mayaAscii": [0.312, 1.0, 0.747], - "setdress": [0.312, 1.0, 0.747], - "layout": [0.312, 1.0, 0.747], - "vdbcache": [0.312, 1.0, 0.428], - "vrayproxy": [0.258, 0.95, 0.541], - "yeticache": [0.2, 0.8, 0.3], - "yetiRig": [0, 0.8, 0.5] - } + "colors": { + "model": [ + 0.821, + 0.518, + 0.117 + ], + "rig": [ + 0.144, + 0.443, + 0.463 + ], + "pointcache": [ + 0.368, + 0.821, + 0.117 + ], + "animation": [ + 0.368, + 0.821, + 0.117 + ], + "ass": [ + 1.0, + 0.332, + 0.312 + ], + "camera": [ + 0.447, + 0.312, + 1.0 + ], + "fbx": [ + 1.0, + 0.931, + 0.312 + ], + "mayaAscii": [ + 0.312, + 1.0, + 0.747 + ], + "setdress": [ + 0.312, + 1.0, + 0.747 + ], + "layout": [ + 0.312, + 1.0, + 0.747 + ], + "vdbcache": [ + 0.312, + 1.0, + 0.428 + ], + "vrayproxy": [ + 0.258, + 0.95, + 0.541 + ], + "yeticache": [ + 0.2, + 0.8, + 0.3 + ], + "yetiRig": [ + 0.0, + 0.8, + 0.5 + ] + } }, "workfile_build": { "profiles": [ diff --git a/pype/settings/defaults/project_settings/standalonepublisher.json b/pype/settings/defaults/project_settings/standalonepublisher.json index 877055ceef..b8015f2832 100644 --- a/pype/settings/defaults/project_settings/standalonepublisher.json +++ b/pype/settings/defaults/project_settings/standalonepublisher.json @@ -19,7 +19,7 @@ "create_camera": "Camera", "create_editorial": "Editorial", "create_image": "Image", - "create_matchmove": "matchmove", + "create_matchmove": "Matchmove", "": "" }, "create_workfile": { @@ -112,7 +112,7 @@ }, "create_matchmove": { "name": "matchmove", - "label": "Matchmove script", + "label": "Matchmove Scripts", "family": "matchmove", "icon": "empire", "defaults": [ @@ -123,4 +123,4 @@ "help": "Script exported from matchmoving application" } } -} \ No newline at end of file +} diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_main.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_main.json index f0226446ea..5b3c399666 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_main.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_main.json @@ -10,7 +10,7 @@ "type": "anatomy_roots", "key": "roots", "is_file": true - }, + }, { "type": "schema", "name": "schema_anatomy_templates" @@ -48,6 +48,10 @@ "type": "schema", "name": "schema_project_hiero" }, + { + "type": "schema", + "name": "schema_project_harmony" + }, { "type": "schema", "name": "schema_project_celaction" From a81923aeee8e65359739ab70061bfbd752c5a492 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 17:23:27 +0100 Subject: [PATCH 249/279] action create folders use settings --- .../ftrack/actions/action_create_folders.py | 40 ++++++++++++------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/pype/modules/ftrack/actions/action_create_folders.py b/pype/modules/ftrack/actions/action_create_folders.py index e689e0260c..a131a0e35b 100644 --- a/pype/modules/ftrack/actions/action_create_folders.py +++ b/pype/modules/ftrack/actions/action_create_folders.py @@ -1,7 +1,11 @@ import os from pype.modules.ftrack.lib import BaseAction, statics_icon from avalon import lib as avalonlib -from pype.api import config, Anatomy +from pype.api import ( + Anatomy, + get_project_settings +) +from pype.lib import ApplicationManager class CreateFolders(BaseAction): @@ -93,6 +97,7 @@ class CreateFolders(BaseAction): all_entities = self.get_notask_children(entity) anatomy = Anatomy(project_name) + project_settings = get_project_settings(project_name) work_keys = ["work", "folder"] work_template = anatomy.templates @@ -106,10 +111,13 @@ class CreateFolders(BaseAction): publish_template = publish_template[key] publish_has_apps = "{app" in publish_template - presets = config.get_presets() - app_presets = presets.get("tools", {}).get("sw_folders") - cached_apps = {} + tools_settings = project_settings["global"]["tools"] + app_presets = tools_settings["Workfiles"]["sw_folders"] + app_manager_apps = None + if app_presets and (work_has_apps or publish_has_apps): + app_manager_apps = ApplicationManager().applications + cached_apps = {} collected_paths = [] for entity in all_entities: if entity.entity_type.lower() == "project": @@ -140,18 +148,20 @@ class CreateFolders(BaseAction): task_data["task"] = child["name"] apps = [] - if app_presets and (work_has_apps or publish_has_apps): - possible_apps = app_presets.get(task_type_name, []) - for app in possible_apps: - if app in cached_apps: - app_dir = cached_apps[app] + if app_manager_apps: + possible_apps = app_presets.get(task_type_name) or [] + for app_name in possible_apps: + + if app_name in cached_apps: + apps.append(cached_apps[app_name]) + continue + + app_def = app_manager_apps.get(app_name) + if app_def and app_def.is_host: + app_dir = app_def.host_name else: - try: - app_data = avalonlib.get_application(app) - app_dir = app_data["application_dir"] - except ValueError: - app_dir = app - cached_apps[app] = app_dir + app_dir = app_name + cached_apps[app_name] = app_dir apps.append(app_dir) # Template wok From 467aa65aa74ed97c56d01bd5a14d7d628bc9d26f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 17:38:43 +0100 Subject: [PATCH 250/279] remove loading clockify presets in ftrack event subprocess --- .../ftrack_server/sub_event_processor.py | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/pype/modules/ftrack/ftrack_server/sub_event_processor.py b/pype/modules/ftrack/ftrack_server/sub_event_processor.py index 4a3241dd4f..c719c8fd08 100644 --- a/pype/modules/ftrack/ftrack_server/sub_event_processor.py +++ b/pype/modules/ftrack/ftrack_server/sub_event_processor.py @@ -9,7 +9,7 @@ from pype.modules.ftrack.ftrack_server.lib import ( SocketSession, ProcessEventHub, TOPIC_STATUS_SERVER ) import ftrack_api -from pype.api import Logger, config +from pype.api import Logger log = Logger().get_logger("Event processor") @@ -56,32 +56,16 @@ def register(session): def clockify_module_registration(): - module_name = "Clockify" - - menu_items = config.get_presets()["tray"]["menu_items"] - if not menu_items["item_usage"][module_name]: - return - api_key = os.environ.get("CLOCKIFY_API_KEY") if not api_key: log.warning("Clockify API key is not set.") return workspace_name = os.environ.get("CLOCKIFY_WORKSPACE") - if not workspace_name: - workspace_name = ( - menu_items - .get("attributes", {}) - .get(module_name, {}) - .get("workspace_name", {}) - ) - if not workspace_name: log.warning("Clockify Workspace is not set.") return - os.environ["CLOCKIFY_WORKSPACE"] = workspace_name - from pype.modules.clockify.constants import CLOCKIFY_FTRACK_SERVER_PATH current = os.environ.get("FTRACK_EVENTS_PATH") or "" From 38c9b093b5e3b96c1342f67a1bc4d4b49ccbc5d4 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 17:51:26 +0100 Subject: [PATCH 251/279] fix review settings --- .../defaults/project_settings/global.json | 46 +++++++++---------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/pype/settings/defaults/project_settings/global.json b/pype/settings/defaults/project_settings/global.json index 7cedd7cf88..5f76f2d0f6 100644 --- a/pype/settings/defaults/project_settings/global.json +++ b/pype/settings/defaults/project_settings/global.json @@ -27,12 +27,12 @@ "video_filters": [], "audio_filters": [], "input": [ - "gamma 2.2" + "-gamma 2.2" ], "output": [ - "pix_fmt yuv420p", - "crf 18", - "intra" + "-pix_fmt yuv420p", + "-crf 18", + "-intra" ] }, "filter": { @@ -76,18 +76,16 @@ }, "IntegrateAssetNew": { "template_name_profiles": { - "template_name_profiles": { - "publish": { - "families": [], - "tasks": [] - }, - "render": { - "families": [ - "review", - "render", - "prerender" - ] - } + "publish": { + "families": [], + "tasks": [] + }, + "render": { + "families": [ + "review", + "render", + "prerender" + ] } } }, @@ -135,15 +133,13 @@ } }, "Workfiles": { - "last_workfile_on_startup": { - "profiles": [ - { - "hosts": [], - "tasks": [], - "enabled": true - } - ] - }, + "last_workfile_on_startup": [ + { + "hosts": [], + "tasks": [], + "enabled": true + } + ], "sw_folders": { "compositing": [ "nuke", From 0fcfde7c0527da57a7c4c9112038edbadb0b8014 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 17:51:53 +0100 Subject: [PATCH 252/279] last workfile on statup from settings --- pype/hooks/global/pre_global_host_data.py | 19 ++--- .../schemas/schema_global_tools.json | 70 +++++++++---------- 2 files changed, 37 insertions(+), 52 deletions(-) diff --git a/pype/hooks/global/pre_global_host_data.py b/pype/hooks/global/pre_global_host_data.py index 3f403b43f5..09fc707e4e 100644 --- a/pype/hooks/global/pre_global_host_data.py +++ b/pype/hooks/global/pre_global_host_data.py @@ -6,7 +6,7 @@ import copy from pype.api import ( Anatomy, - config + get_project_settings ) from pype.lib import ( env_value_to_bool, @@ -284,20 +284,9 @@ class GlobalHostDataHook(PreLaunchHook): bool: True if host should start workfile. """ - default_output = env_value_to_bool( - "AVALON_OPEN_LAST_WORKFILE", default=False - ) - # TODO convert to settings - try: - startup_presets = ( - config.get_presets(project_name) - .get("tools", {}) - .get("workfiles", {}) - .get("last_workfile_on_startup") - ) - except Exception: - startup_presets = None - self.log.warning("Couldn't load pype's presets", exc_info=True) + + project_settings = get_project_settings(project_name)['global']['tools'] + startup_presets = project_settings['Workfiles']['last_workfile_on_startup'] if not startup_presets: return default_output diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_global_tools.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_global_tools.json index 5a19e4827d..529794fd28 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_global_tools.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_global_tools.json @@ -28,45 +28,41 @@ "label": "Workfiles", "children": [ { - "type": "dict", - "collapsable": true, - "key": "last_workfile_on_startup", + "type": "collapsible-wrap", "label": "Open last workfiles on launch", - "checkbox_key": "enabled", - "is_group": true, "children": [ - { - "type": "list", - "key": "profiles", - "label": "Profiles", - "object_type": - { - "type": "dict", - "children": [ - { - "key": "hosts", - "label": "Hosts", - "type": "list", - "object_type": "text" - }, - { - "key": "tasks", - "label": "Tasks", - "type": "list", - "object_type": "text" - }, - { - "type": "splitter" - }, - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - } - ] - } - } - ] + { + "type": "list", + "key": "last_workfile_on_startup", + "label": "", + "is_group": true, + "object_type": + { + "type": "dict", + "children": [ + { + "key": "hosts", + "label": "Hosts", + "type": "list", + "object_type": "text" + }, + { + "key": "tasks", + "label": "Tasks", + "type": "list", + "object_type": "text" + }, + { + "type": "splitter" + }, + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + } + ] + } + }] }, { "type": "dict-modifiable", From 49cfd19a160c104623652fe42c751076aacaec3f Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 17:54:40 +0100 Subject: [PATCH 253/279] convert unreal to settings --- pype/hosts/unreal/lib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/hosts/unreal/lib.py b/pype/hosts/unreal/lib.py index d6bfba436e..c356193ea0 100644 --- a/pype/hosts/unreal/lib.py +++ b/pype/hosts/unreal/lib.py @@ -4,7 +4,7 @@ import platform import json from distutils import dir_util import subprocess -from pype.api import config +from pype.api import get_current_project_settings def get_engine_versions(): @@ -150,7 +150,7 @@ def create_unreal_project(project_name: str, :type dev_mode: bool :returns: None """ - preset = config.get_presets()["unreal"]["project_setup"] + preset = get_current_project_settings()["unreal"]["project_setup"] if os.path.isdir(os.environ.get("AVALON_UNREAL_PLUGIN", "")): # copy plugin to correct path under project From 379560a224ddad521ed5e3091963faa515322a3e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 18:04:54 +0100 Subject: [PATCH 254/279] post ftrack change is using settings --- pype/hooks/global/post_ftrack_changes.py | 29 +++++++++++++++++------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/pype/hooks/global/post_ftrack_changes.py b/pype/hooks/global/post_ftrack_changes.py index 144f618620..4dc45f5419 100644 --- a/pype/hooks/global/post_ftrack_changes.py +++ b/pype/hooks/global/post_ftrack_changes.py @@ -1,7 +1,7 @@ import os import ftrack_api -from pype.api import config +from pype.api import get_project_settings from pype.lib import PostLaunchHook @@ -101,10 +101,23 @@ class PostFtrackHook(PostLaunchHook): return filtered_entities[0] def ftrack_status_change(self, session, entity, project_name): - # TODO use settings - presets = config.get_presets(project_name)["ftrack"]["ftrack_config"] - statuses = presets.get("status_update") - if not statuses: + project_settings = get_project_settings(project_name) + status_update = project_settings["ftrack"]["events"]["status_update"] + if not status_update["enabled"]: + self.log.debug( + "Status changes are disabled for project \"{}\"".format( + project_name + ) + ) + return + + status_mapping = status_update["mapping"] + if not status_mapping: + self.log.warning( + "Project \"{}\" does not have set status changes.".format( + project_name + ) + ) return actual_status = entity["status"]["name"].lower() @@ -114,11 +127,11 @@ class PostFtrackHook(PostLaunchHook): ) while True: next_status_name = None - for key, value in statuses.items(): + for key, value in status_mapping.items(): if key in already_tested: continue - if actual_status in value or "_any_" in value: - if key != "_ignore_": + if actual_status in value or "__any__" in value: + if key != "__ignore__": next_status_name = key already_tested.add(key) break From 27fbe814f506de965aa1f817921deb3031f3ac29 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 18:12:13 +0100 Subject: [PATCH 255/279] change preset collecting to settings --- .../plugins/global/publish/collect_presets.py | 22 +++---------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/pype/plugins/global/publish/collect_presets.py b/pype/plugins/global/publish/collect_presets.py index 4ffb2fc0b3..95fb4dbfad 100644 --- a/pype/plugins/global/publish/collect_presets.py +++ b/pype/plugins/global/publish/collect_presets.py @@ -8,7 +8,7 @@ Provides: """ from pyblish import api -from pype.api import config +from pype.api import get_current_project_settings class CollectPresets(api.ContextPlugin): @@ -18,23 +18,7 @@ class CollectPresets(api.ContextPlugin): label = "Collect Presets" def process(self, context): - presets = config.get_presets() - try: - # try if it is not in projects custom directory - # `{PYPE_PROJECT_CONFIGS}/[PROJECT_NAME]/init.json` - # init.json define preset names to be used - p_init = presets["init"] - presets["colorspace"] = presets["colorspace"][p_init["colorspace"]] - presets["dataflow"] = presets["dataflow"][p_init["dataflow"]] - except KeyError: - self.log.warning("No projects custom preset available...") - presets["colorspace"] = presets["colorspace"]["default"] - presets["dataflow"] = presets["dataflow"]["default"] - self.log.info( - "Presets `colorspace` and `dataflow` loaded from `default`..." - ) + project_settings = get_current_project_settings() + context.data["presets"] = project_settings - context.data["presets"] = presets - - # self.log.info(context.data["presets"]) return From c8c6902ae8f7a43cbc7d684b6d6e22064a49aa8f Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 18:18:55 +0100 Subject: [PATCH 256/279] remove legacy preset loading --- pype/plugins/maya/publish/extract_camera_mayaScene.py | 1 + pype/scripts/otio_burnin.py | 7 ------- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/pype/plugins/maya/publish/extract_camera_mayaScene.py b/pype/plugins/maya/publish/extract_camera_mayaScene.py index 8fce48badf..a01c5885b0 100644 --- a/pype/plugins/maya/publish/extract_camera_mayaScene.py +++ b/pype/plugins/maya/publish/extract_camera_mayaScene.py @@ -102,6 +102,7 @@ class ExtractCameraMayaScene(pype.api.Extractor): def process(self, instance): """Plugin entry point.""" # get settings + # TODO: load all settings directly, rather than passing them through context ext_mapping = instance.context.data["presets"]["maya"].get("ext_mapping") # noqa: E501 if ext_mapping: self.log.info("Looking in presets for scene type ...") diff --git a/pype/scripts/otio_burnin.py b/pype/scripts/otio_burnin.py index 0bd636c6c5..dfa94adf1f 100644 --- a/pype/scripts/otio_burnin.py +++ b/pype/scripts/otio_burnin.py @@ -428,13 +428,6 @@ def burnins_from_data( } """ - # Use legacy processing when options are not set - # TODO: remove legacy review - if options is None or burnin_values is None: - presets = config.get_presets().get("tools", {}).get("burnins", {}) - options = presets.get("options") - burnin_values = presets.get("burnins") or {} - burnin = ModifiedBurnins(input_path, options_init=options) frame_start = data.get("frame_start") From d513d47695fb53947c5c8d3d741661cc412197be Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 18:27:58 +0100 Subject: [PATCH 257/279] remove slate presets --- pype/scripts/slates/slate_base/lib.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/pype/scripts/slates/slate_base/lib.py b/pype/scripts/slates/slate_base/lib.py index 6b0c01883c..ec283e0e22 100644 --- a/pype/scripts/slates/slate_base/lib.py +++ b/pype/scripts/slates/slate_base/lib.py @@ -12,11 +12,6 @@ from .items import ( ItemTable, ItemImage, ItemRectangle, ItemPlaceHolder ) -try: - from pype.api.config import get_presets -except Exception: - get_presets = dict - log = logging.getLogger(__name__) @@ -41,11 +36,7 @@ def create_slates( ) elif slate_data is None: - slate_presets = ( - get_presets() - .get("tools", {}) - .get("slates") - ) or {} + slate_presets = {} slate_data = slate_presets.get(slate_name) if slate_data is None: raise ValueError( From 44df16bf681d21efcb6ad2081eaac7a9045e8a9b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 18:30:10 +0100 Subject: [PATCH 258/279] add short task names to anatomy attributes --- .../defaults/project_anatomy/attributes.json | 18 +++++++++++++++++- .../schemas/schema_anatomy_attributes.json | 6 ++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/pype/settings/defaults/project_anatomy/attributes.json b/pype/settings/defaults/project_anatomy/attributes.json index fbf0218999..8f35e41533 100644 --- a/pype/settings/defaults/project_anatomy/attributes.json +++ b/pype/settings/defaults/project_anatomy/attributes.json @@ -9,5 +9,21 @@ "resolutionWidth": 1920, "resolutionHeight": 1080, "pixelAspect": 1, - "applications": [] + "applications": [], + "task_short_names": { + "Generic": "gener", + "Art": "art", + "Modeling": "mdl", + "Texture": "tex", + "Lookdev": "look", + "Rigging": "rig", + "Edit": "edit", + "Layout": "lay", + "Setdress": "dress", + "Animation": "anim", + "FX": "fx", + "Lighting": "lgt", + "Paint": "paint", + "Compositing": "comp" + } } \ No newline at end of file diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_anatomy_attributes.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_anatomy_attributes.json index 1ede46903c..a64b99ce9d 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_anatomy_attributes.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schemas/schema_anatomy_attributes.json @@ -68,6 +68,12 @@ {"blender_2.91": "Blender 2.91"}, {"aftereffects_2021": "After Effects 2021"} ] + }, + { + "type": "dict-modifiable", + "key": "task_short_names", + "label": "Task short names (by Task type)", + "object_type": "text" } ] } From f25ba30bffa4da3a65138119d395d6085ff363de Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 18:30:18 +0100 Subject: [PATCH 259/279] fix unreal settings --- pype/hosts/unreal/lib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/hosts/unreal/lib.py b/pype/hosts/unreal/lib.py index c356193ea0..02b1ae5bf5 100644 --- a/pype/hosts/unreal/lib.py +++ b/pype/hosts/unreal/lib.py @@ -4,7 +4,7 @@ import platform import json from distutils import dir_util import subprocess -from pype.api import get_current_project_settings +from pype.api import get_project_settings def get_engine_versions(): @@ -150,7 +150,7 @@ def create_unreal_project(project_name: str, :type dev_mode: bool :returns: None """ - preset = get_current_project_settings()["unreal"]["project_setup"] + preset = get_project_settings(project_name)["unreal"]["project_setup"] if os.path.isdir(os.environ.get("AVALON_UNREAL_PLUGIN", "")): # copy plugin to correct path under project From 7889b2a360116be4218366395219bee39ea41fe5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 18:46:09 +0100 Subject: [PATCH 260/279] don't use get_presets in avalon_sync --- pype/modules/ftrack/lib/avalon_sync.py | 42 +++++++++----------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/pype/modules/ftrack/lib/avalon_sync.py b/pype/modules/ftrack/lib/avalon_sync.py index a379aa9900..0716a5975f 100644 --- a/pype/modules/ftrack/lib/avalon_sync.py +++ b/pype/modules/ftrack/lib/avalon_sync.py @@ -8,13 +8,12 @@ import copy from avalon.api import AvalonMongoDB import avalon -from pype.api import Logger, Anatomy +from pype.api import Logger, Anatomy, get_anatomy_data from bson.objectid import ObjectId from bson.errors import InvalidId from pymongo import UpdateOne import ftrack_api -from pype.api import config from pype.lib import ApplicationManager log = Logger().get_logger(__name__) @@ -276,28 +275,6 @@ def get_hierarchical_attributes(session, entity, attr_names, attr_defaults={}): return hier_values -def get_task_short_name(task_type): - """ - Returns short name (code) for 'task_type'. Short name stored in - metadata dictionary in project.config per each 'task_type'. - Could be used in anatomy, paths etc. - If no appropriate short name is found in mapping, 'task_type' is - returned back unchanged. - - Currently stores data in: - 'pype-config/presets/ftrack/project_defaults.json' - Args: - task_type: (string) - Animation | Modeling ... - - Returns: - (string) - anim | model ... - """ - presets = config.get_presets()['ftrack']['project_defaults']\ - .get("task_short_names") - - return presets.get(task_type, task_type) - - class SyncEntitiesFactory: dbcon = AvalonMongoDB() @@ -1118,6 +1095,13 @@ class SyncEntitiesFactory: ) def prepare_ftrack_ent_data(self): + project_name = self.entities_dict[self.ft_project_id]["name"] + project_anatomy_data = get_anatomy_data(project_name) + + task_type_mapping = ( + project_anatomy_data["attributes"]["task_short_names"] + ) + not_set_ids = [] for id, entity_dict in self.entities_dict.items(): entity = entity_dict["entity"] @@ -1154,10 +1138,12 @@ class SyncEntitiesFactory: continue self.report_items["warning"][msg] = items tasks = {} - for tt in task_types: - tasks[tt["name"]] = { - "short_name": get_task_short_name(tt["name"]) - } + for task_type in task_types: + task_type_name = task_type["name"] + short_name = task_type_mapping.get(task_type_name) + tasks[task_type_name] = { + "short_name": short_name or task_type_name + } self.entities_dict[id]["final_entity"]["config"] = { "tasks": tasks, "apps": proj_apps From cdf7b820e92756ecd050051338424802e4e1b46e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 18:58:40 +0100 Subject: [PATCH 261/279] pype tray modified to use settings --- pype/tools/tray/pype_tray.py | 38 +++++++++++++----------------------- 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/pype/tools/tray/pype_tray.py b/pype/tools/tray/pype_tray.py index a4cf4eabfe..81a628fdb5 100644 --- a/pype/tools/tray/pype_tray.py +++ b/pype/tools/tray/pype_tray.py @@ -3,7 +3,8 @@ import sys import platform from avalon import style from Qt import QtCore, QtGui, QtWidgets, QtSvg -from pype.api import config, Logger, resources +from pype.api import Logger, resources +from pype.settings.lib import get_system_settings, load_json_file import pype.version try: import configparser @@ -31,18 +32,11 @@ class TrayManager: self.errors = [] CURRENT_DIR = os.path.dirname(__file__) - self.modules_imports = config.load_json( + self.modules_imports = load_json_file( os.path.join(CURRENT_DIR, "modules_imports.json") ) - presets = config.get_presets(first_run=True) - menu_items = presets["tray"]["menu_items"] - try: - self.modules_usage = menu_items["item_usage"] - except Exception: - self.modules_usage = {} - self.log.critical("Couldn't find modules usage data.") - - self.module_attributes = menu_items.get("attributes") or {} + module_settings = get_system_settings()["modules"] + self.module_settings = module_settings self.icon_run = QtGui.QIcon( resources.get_resource("icons", "circle_green.png") @@ -75,23 +69,19 @@ class TrayManager: import_path = item.get("import_path") title = item.get("title") - item_usage = self.modules_usage.get(title) - if item_usage is None: - item_usage = self.modules_usage.get(import_path, True) - - if not item_usage: + module_data = self.module_settings.get(title) + if not module_data: if not title: title = import_path - self.log.info("{} - Module ignored".format(title)) + self.log.warning("{} - Module data not found".format(title)) continue - _attributes = self.module_attributes.get(title) - if _attributes is None: - _attributes = self.module_attributes.get(import_path) - - if _attributes: - item["attributes"] = _attributes + enabled = module_data.pop("enabled", True) + if not enabled: + self.log.debug("{} - Module is disabled".format(title)) + continue + item["attributes"] = module_data items.append(item) if items: @@ -207,7 +197,7 @@ class TrayManager: ) klass = getattr(module, "CLASS_DEFINIION", None) if not klass and attributes: - self.log.error(( + self.log.debug(( "There are defined attributes for module \"{}\" but" "module does not have defined \"CLASS_DEFINIION\"." ).format(import_path)) From 57b1cc7cd171c2f57c9c7bd9769e36857db727f1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 19:00:33 +0100 Subject: [PATCH 262/279] turn of clockify by default --- pype/settings/defaults/system_settings/modules.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/settings/defaults/system_settings/modules.json b/pype/settings/defaults/system_settings/modules.json index 4a91d2dddf..a36a3b75cf 100644 --- a/pype/settings/defaults/system_settings/modules.json +++ b/pype/settings/defaults/system_settings/modules.json @@ -166,7 +166,7 @@ "message_time": 0.5 }, "Clockify": { - "enabled": true, + "enabled": false, "workspace_name": "studio name" }, "Deadline": { From 31a2c70b26c7cce67806334c35352e3bb2ccf0d4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 19:29:13 +0100 Subject: [PATCH 263/279] implemented `clear_metadata_from_settings` to remove metadata from loaded settings --- pype/settings/lib.py | 61 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index 33a427c3a6..1189b1ab2a 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -17,6 +17,13 @@ M_DYNAMIC_KEY_LABEL = "__dynamic_keys_labels__" # NOTE key popping not implemented yet M_POP_KEY = "__pop_key__" +METADATA_KEYS = ( + M_OVERRIDEN_KEY, + M_ENVIRONMENT_KEY, + M_DYNAMIC_KEY_LABEL, + M_POP_KEY +) + # Folder where studio overrides are stored STUDIO_OVERRIDES_PATH = os.getenv("PYPE_PROJECT_CONFIGS") or "" @@ -413,30 +420,37 @@ def apply_overrides(source_data, override_data): return merge_overrides(_source_data, override_data) -def get_system_settings(): +def get_system_settings(clear_metadata=True): """System settings with applied studio overrides.""" default_values = get_default_settings()[SYSTEM_SETTINGS_KEY] studio_values = get_studio_system_settings_overrides() - return apply_overrides(default_values, studio_values) + result = apply_overrides(default_values, studio_values) + if clear_metadata: + clear_metadata_from_settings(result) + return result -def get_default_project_settings(): +def get_default_project_settings(clear_metadata=True): """Project settings with applied studio's default project overrides.""" default_values = get_default_settings()[PROJECT_SETTINGS_KEY] studio_values = get_studio_project_settings_overrides() - - return apply_overrides(default_values, studio_values) + result = apply_overrides(default_values, studio_values) + if clear_metadata: + clear_metadata_from_settings(result) + return result -def get_default_project_anatomy_data(): +def get_default_project_anatomy_data(clear_metadata=True): """Project anatomy data with applied studio's default project overrides.""" default_values = get_default_settings()[PROJECT_ANATOMY_KEY] studio_values = get_studio_project_anatomy_overrides() - - return apply_overrides(default_values, studio_values) + result = apply_overrides(default_values, studio_values) + if clear_metadata: + clear_metadata_from_settings(result) + return result -def get_anatomy_data(project_name): +def get_anatomy_data(project_name, clear_metadata=True): """Project anatomy data with applied studio and project overrides.""" if not project_name: raise ValueError( @@ -444,13 +458,16 @@ def get_anatomy_data(project_name): " Call `get_default_project_anatomy_data` to get project defaults." ) - studio_overrides = get_default_project_anatomy_data() + studio_overrides = get_default_project_anatomy_data(False) project_overrides = get_project_anatomy_overrides(project_name) - return apply_overrides(studio_overrides, project_overrides) + result = apply_overrides(studio_overrides, project_overrides) + if clear_metadata: + clear_metadata_from_settings(result) + return result -def get_project_settings(project_name): +def get_project_settings(project_name, clear_metadata=True): """Project settings with applied studio and project overrides.""" if not project_name: raise ValueError( @@ -458,10 +475,13 @@ def get_project_settings(project_name): " Call `get_default_project_settings` to get project defaults." ) - studio_overrides = get_default_project_settings() + studio_overrides = get_default_project_settings(False) project_overrides = get_project_settings_overrides(project_name) - return apply_overrides(studio_overrides, project_overrides) + result = apply_overrides(studio_overrides, project_overrides) + if clear_metadata: + clear_metadata_from_settings(result) + return result def get_current_project_settings(): @@ -491,3 +511,16 @@ def get_environments(): """ return find_environments(get_system_settings()) + + +def clear_metadata_from_settings(values): + """Remove all metadata keys from loaded settings.""" + if isinstance(values, dict): + for key in tuple(values.keys()): + if key in METADATA_KEYS: + values.pop(key) + else: + clear_metadata_from_settings(values[key]) + elif isinstance(values, list): + for item in values: + clear_metadata_from_settings(item) From c8e0a2e414b013ab9940ff6e033ce6aa61609be2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 19:30:58 +0100 Subject: [PATCH 264/279] removed as syntax --- pype/modules/ftrack/actions/action_create_project_structure.py | 2 +- pype/modules/ftrack/events/event_user_assigment.py | 2 +- pype/modules/ftrack/events/event_version_to_task_statuses.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pype/modules/ftrack/actions/action_create_project_structure.py b/pype/modules/ftrack/actions/action_create_project_structure.py index 4fc59da89e..1f7dfcec0b 100644 --- a/pype/modules/ftrack/actions/action_create_project_structure.py +++ b/pype/modules/ftrack/actions/action_create_project_structure.py @@ -2,7 +2,7 @@ import os import re from pype.modules.ftrack.lib import BaseAction, statics_icon -from pype.api import Anatomy, get_project_settings as get_project_settings +from pype.api import Anatomy, get_project_settings class CreateProjectFolders(BaseAction): diff --git a/pype/modules/ftrack/events/event_user_assigment.py b/pype/modules/ftrack/events/event_user_assigment.py index 6a230f6ff9..f65c2334b0 100644 --- a/pype/modules/ftrack/events/event_user_assigment.py +++ b/pype/modules/ftrack/events/event_user_assigment.py @@ -8,7 +8,7 @@ from avalon.api import AvalonMongoDB from bson.objectid import ObjectId -from pype.api import Anatomy, get_project_settings as get_project_settings +from pype.api import Anatomy, get_project_settings class UserAssigmentEvent(BaseEvent): diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index ca55f24f32..39384e996e 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -1,5 +1,5 @@ from pype.modules.ftrack import BaseEvent -from pype.api import get_project_settings as get_project_settings +from pype.api import get_project_settings class VersionToTaskStatus(BaseEvent): From fbb0f5ffca5666934ae80eb5da68f11ad672fcf6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 19:35:41 +0100 Subject: [PATCH 265/279] renamed `get_anatomy_data` to `get_anatomy_settings` --- pype/settings/__init__.py | 4 ++-- pype/settings/lib.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pype/settings/__init__.py b/pype/settings/__init__.py index 479236b99a..6f06b89460 100644 --- a/pype/settings/__init__.py +++ b/pype/settings/__init__.py @@ -2,7 +2,7 @@ from .lib import ( get_system_settings, get_project_settings, get_current_project_settings, - get_anatomy_data, + get_anatomy_settings, get_environments ) @@ -10,6 +10,6 @@ __all__ = ( "get_system_settings", "get_project_settings", "get_current_project_settings", - "get_anatomy_data", + "get_anatomy_settings", "get_environments" ) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index 33a427c3a6..3d076ae64c 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -436,7 +436,7 @@ def get_default_project_anatomy_data(): return apply_overrides(default_values, studio_values) -def get_anatomy_data(project_name): +def get_anatomy_settings(project_name): """Project anatomy data with applied studio and project overrides.""" if not project_name: raise ValueError( From e7f0af72d820247cf2b05e5a4c5ca41a2fbf288d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 19:36:05 +0100 Subject: [PATCH 266/279] renamed `get_default_project_anatomy_data` to `get_default_anatomy_settings` --- pype/settings/lib.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index 3d076ae64c..03c888faa7 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -428,7 +428,7 @@ def get_default_project_settings(): return apply_overrides(default_values, studio_values) -def get_default_project_anatomy_data(): +def get_default_anatomy_settings(): """Project anatomy data with applied studio's default project overrides.""" default_values = get_default_settings()[PROJECT_ANATOMY_KEY] studio_values = get_studio_project_anatomy_overrides() @@ -440,11 +440,11 @@ def get_anatomy_settings(project_name): """Project anatomy data with applied studio and project overrides.""" if not project_name: raise ValueError( - "Must enter project name." - " Call `get_default_project_anatomy_data` to get project defaults." + "Must enter project name. Call " + "`get_default_anatomy_settings` to get project defaults." ) - studio_overrides = get_default_project_anatomy_data() + studio_overrides = get_default_anatomy_settings() project_overrides = get_project_anatomy_overrides(project_name) return apply_overrides(studio_overrides, project_overrides) From d8b94cca5cd4c15f9aa8b297858835a63bf53f6b Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 20:45:32 +0100 Subject: [PATCH 267/279] remove unused config imports --- pype/lib/plugin_tools.py | 2 +- pype/scripts/otio_burnin.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/lib/plugin_tools.py b/pype/lib/plugin_tools.py index 726726bb4c..a78c9e525e 100644 --- a/pype/lib/plugin_tools.py +++ b/pype/lib/plugin_tools.py @@ -4,7 +4,7 @@ import os import inspect import logging -from ..api import config, get_project_settings +from ..api import get_project_settings log = logging.getLogger(__name__) diff --git a/pype/scripts/otio_burnin.py b/pype/scripts/otio_burnin.py index dfa94adf1f..4f5c290e9d 100644 --- a/pype/scripts/otio_burnin.py +++ b/pype/scripts/otio_burnin.py @@ -5,7 +5,7 @@ import subprocess import platform import json import opentimelineio_contrib.adapters.ffmpeg_burnins as ffmpeg_burnins -from pype.api import config, resources +from pype.api import resources import pype.lib From 01c1ae89117f91fbea86bb29b537855b69bc65db Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 20:45:58 +0100 Subject: [PATCH 268/279] asset creator tool uses settings (hidden for now) --- .../ftrack/project_schemas/default.json | 39 +++++++++++++++++++ pype/tools/assetcreator/app.py | 4 +- 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 pype/settings/defaults/project_settings/ftrack/project_schemas/default.json diff --git a/pype/settings/defaults/project_settings/ftrack/project_schemas/default.json b/pype/settings/defaults/project_settings/ftrack/project_schemas/default.json new file mode 100644 index 0000000000..a90a0b3a8b --- /dev/null +++ b/pype/settings/defaults/project_settings/ftrack/project_schemas/default.json @@ -0,0 +1,39 @@ +{ + "object_types": ["Milestone", "Task", "Folder", "Asset Build", "Shot", "Library", "Sequence"], + "version_workflow": ["Pending Review", "Client Review", "On Farm", "Reviewed", "Render Complete", "Approved", "CBB", "Delivered", "Render Failed", "data"], + "task_workflow": ["Not Ready", "Ready", "Change Requested", "In progress", "Pending Review", "On Farm", "Waiting", "Render Complete", "Complete", "CBB", "On Hold", "Render Failed", "Omitted"], + "overrides": [{ + "task_types": ["Animation"], + "statuses": ["Not Ready", "Ready", "Change Requested", "Blocking", "Animating", "blocking review", "anim review", "Complete", "CBB", "On Hold", "Omitted"] + }, { + "task_types": ["Lighting"], + "statuses": ["Not Ready", "Ready", "Change Requested", "In progress", "To render", "On Farm", "Render Complete", "Complete", "CBB", "On Hold", "Render Failed", "Omitted"] + }], + "task_type_schema": ["Layout", "Animation", "Modeling", "Previz", "Lookdev", "FX", "Lighting", "Compositing", "Rigging", "Texture", "Matte-paint", "Roto-paint", "Art", "Match-moving", "Production", "Build", "Setdress", "Edit", "R&D", "Boards"], + "schemas": [{ + "object_type": "Shot", + "statuses": ["Omitted", "Normal", "Complete"], + "task_types": [] + }, { + "object_type": "Asset Build", + "statuses": ["Omitted", "Normal", "Complete"], + "task_types": ["Setups", "Sets", "Characters", "Props", "Locations", "Assembly", "R&D", "Elements"] + }, { + "object_type": "Milestone", + "statuses": ["Normal", "Complete"], + "task_types": ["Generic"] + }], + "task_templates": [{ + "name": "Character", + "task_types": ["Art", "Modeling", "Lookdev", "Rigging"] + }, { + "name": "Element", + "task_types": ["Modeling", "Lookdev"] + }, { + "name": "Prop", + "task_types": ["Modeling", "Lookdev", "Rigging"] + }, { + "name": "Location", + "task_types": ["Layout", "Setdress"] + }] +} \ No newline at end of file diff --git a/pype/tools/assetcreator/app.py b/pype/tools/assetcreator/app.py index 71b1027ef4..f025af9662 100644 --- a/pype/tools/assetcreator/app.py +++ b/pype/tools/assetcreator/app.py @@ -6,7 +6,7 @@ try: import ftrack_api_old as ftrack_api except Exception: import ftrack_api -from pype.api import config +from pype.api import get_current_project_settings from pype import lib as pypelib from avalon.vendor.Qt import QtWidgets, QtCore from avalon import io, api, style, schema @@ -196,7 +196,7 @@ class Window(QtWidgets.QDialog): ft_project = session.query(project_query).one() schema_name = ft_project['project_schema']['name'] # Load config - schemas_items = config.get_presets().get('ftrack', {}).get( + schemas_items = get_current_project_settings().get('ftrack', {}).get( 'project_schemas', {} ) # Get info if it is silo project From f668db28524e74aea87f7a7b5f1b3450e2d71103 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 20:46:20 +0100 Subject: [PATCH 269/279] remove slate example --- .../tools/slates/example_HD.json | 212 ------------------ 1 file changed, 212 deletions(-) delete mode 100644 pype/settings/defaults/project_settings/tools/slates/example_HD.json diff --git a/pype/settings/defaults/project_settings/tools/slates/example_HD.json b/pype/settings/defaults/project_settings/tools/slates/example_HD.json deleted file mode 100644 index b06391fb63..0000000000 --- a/pype/settings/defaults/project_settings/tools/slates/example_HD.json +++ /dev/null @@ -1,212 +0,0 @@ -{ - "width": 1920, - "height": 1080, - "destination_path": "{destination_path}", - "style": { - "*": { - "font-family": "arial", - "font-color": "#ffffff", - "font-bold": false, - "font-italic": false, - "bg-color": "#0077ff", - "alignment-horizontal": "left", - "alignment-vertical": "top" - }, - "layer": { - "padding": 0, - "margin": 0 - }, - "rectangle": { - "padding": 0, - "margin": 0, - "bg-color": "#E9324B", - "fill": true - }, - "main_frame": { - "padding": 0, - "margin": 0, - "bg-color": "#252525" - }, - "table": { - "padding": 0, - "margin": 0, - "bg-color": "transparent" - }, - "table-item": { - "padding": 5, - "padding-bottom": 10, - "margin": 0, - "bg-color": "#212121", - "bg-alter-color": "#272727", - "font-color": "#dcdcdc", - "font-bold": false, - "font-italic": false, - "alignment-horizontal": "left", - "alignment-vertical": "top", - "word-wrap": false, - "ellide": true, - "max-lines": 1 - }, - "table-item-col[0]": { - "font-size": 20, - "font-color": "#898989", - "font-bold": true, - "ellide": false, - "word-wrap": true, - "max-lines": null - }, - "table-item-col[1]": { - "font-size": 40, - "padding-left": 10 - }, - "#colorbar": { - "bg-color": "#9932CC" - } - }, - "items": [{ - "type": "layer", - "direction": 1, - "name": "MainLayer", - "style": { - "#MainLayer": { - "width": 1094, - "height": 1000, - "margin": 25, - "padding": 0 - }, - "#LeftSide": { - "margin-right": 25 - } - }, - "items": [{ - "type": "layer", - "name": "LeftSide", - "items": [{ - "type": "layer", - "direction": 1, - "style": { - "table-item": { - "bg-color": "transparent", - "padding-bottom": 20 - }, - "table-item-col[0]": { - "font-size": 20, - "font-color": "#898989", - "alignment-horizontal": "right" - }, - "table-item-col[1]": { - "alignment-horizontal": "left", - "font-bold": true, - "font-size": 40 - } - }, - "items": [{ - "type": "table", - "values": [ - ["Show:", "{project[name]}"] - ], - "style": { - "table-item-field[0:0]": { - "width": 150 - }, - "table-item-field[0:1]": { - "width": 580 - } - } - }, { - "type": "table", - "values": [ - ["Submitting For:", "{intent}"] - ], - "style": { - "table-item-field[0:0]": { - "width": 160 - }, - "table-item-field[0:1]": { - "width": 218, - "alignment-horizontal": "right" - } - } - }] - }, { - "type": "rectangle", - "style": { - "bg-color": "#bc1015", - "width": 1108, - "height": 5, - "fill": true - } - }, { - "type": "table", - "use_alternate_color": true, - "values": [ - ["Version name:", "{version_name}"], - ["Date:", "{date}"], - ["Shot Types:", "{shot_type}"], - ["Submission Note:", "{submission_note}"] - ], - "style": { - "table-item": { - "padding-bottom": 20 - }, - "table-item-field[0:1]": { - "font-bold": true - }, - "table-item-field[3:0]": { - "word-wrap": true, - "ellide": true, - "max-lines": 4 - }, - "table-item-col[0]": { - "alignment-horizontal": "right", - "width": 150 - }, - "table-item-col[1]": { - "alignment-horizontal": "left", - "width": 958 - } - } - }] - }, { - "type": "layer", - "name": "RightSide", - "items": [{ - "type": "placeholder", - "name": "thumbnail", - "path": "{thumbnail_path}", - "style": { - "width": 730, - "height": 412 - } - }, { - "type": "placeholder", - "name": "colorbar", - "path": "{color_bar_path}", - "return_data": true, - "style": { - "width": 730, - "height": 55 - } - }, { - "type": "table", - "use_alternate_color": true, - "values": [ - ["Vendor:", "{vendor}"], - ["Shot Name:", "{shot_name}"], - ["Frames:", "{frame_start} - {frame_end} ({duration})"] - ], - "style": { - "table-item-col[0]": { - "alignment-horizontal": "left", - "width": 200 - }, - "table-item-col[1]": { - "alignment-horizontal": "right", - "width": 530, - "font-size": 30 - } - } - }] - }] - }] -} From 363b70233d50617ad83aeccab1d4e2d7b70121f7 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 3 Dec 2020 21:48:27 +0100 Subject: [PATCH 270/279] deal with hound --- pype/__init__.py | 7 +++++-- pype/hooks/global/pre_global_host_data.py | 6 ++++-- pype/hosts/harmony/__init__.py | 16 ++++++++++++---- .../actions/action_create_project_structure.py | 4 ++-- .../ftrack/events/event_user_assigment.py | 4 ++-- .../events/event_version_to_task_statuses.py | 5 ++--- .../maya/publish/extract_camera_mayaScene.py | 4 ++-- pype/plugins/maya/publish/submit_maya_muster.py | 3 ++- setup/maya/userSetup.py | 3 ++- 9 files changed, 33 insertions(+), 19 deletions(-) diff --git a/pype/__init__.py b/pype/__init__.py index 8481fa2d48..a2840e271b 100644 --- a/pype/__init__.py +++ b/pype/__init__.py @@ -48,9 +48,12 @@ def patched_discover(superclass): elif superclass.__name__.split(".")[-1] == "Creator": plugin_type = "create" - print(">>> trying to find presets for {}:{} ...".format(host, plugin_type)) + print(">>> Finding presets for {}:{} ...".format(host, plugin_type)) try: - settings = get_project_settings(os.environ['AVALON_PROJECT'])[host][plugin_type] + settings = ( + get_project_settings(os.environ['AVALON_PROJECT']) + [host][plugin_type] + ) except KeyError: print("*** no presets found.") else: diff --git a/pype/hooks/global/pre_global_host_data.py b/pype/hooks/global/pre_global_host_data.py index 09fc707e4e..4910d08010 100644 --- a/pype/hooks/global/pre_global_host_data.py +++ b/pype/hooks/global/pre_global_host_data.py @@ -285,8 +285,10 @@ class GlobalHostDataHook(PreLaunchHook): """ - project_settings = get_project_settings(project_name)['global']['tools'] - startup_presets = project_settings['Workfiles']['last_workfile_on_startup'] + project_settings = ( + get_project_settings(project_name)['global']['tools']) + startup_presets = ( + project_settings['Workfiles']['last_workfile_on_startup']) if not startup_presets: return default_output diff --git a/pype/hosts/harmony/__init__.py b/pype/hosts/harmony/__init__.py index bc91b4db2f..b91c0ad4b1 100644 --- a/pype/hosts/harmony/__init__.py +++ b/pype/hosts/harmony/__init__.py @@ -50,10 +50,18 @@ def get_asset_settings(): } try: - skip_resolution_check = \ - get_current_project_settings()["harmony"]["general"]["skip_resolution_check"] - skip_timelines_check = \ - get_current_project_settings()["harmony"]["general"]["skip_timelines_check"] + skip_resolution_check = ( + get_current_project_settings() + ["harmony"] + ["general"] + ["skip_resolution_check"] + ) + skip_timelines_check = ( + get_current_project_settings() + ["harmony"] + ["general"] + ["skip_timelines_check"] + ) except KeyError: skip_resolution_check = [] skip_timelines_check = [] diff --git a/pype/modules/ftrack/actions/action_create_project_structure.py b/pype/modules/ftrack/actions/action_create_project_structure.py index 1f7dfcec0b..0815f82a69 100644 --- a/pype/modules/ftrack/actions/action_create_project_structure.py +++ b/pype/modules/ftrack/actions/action_create_project_structure.py @@ -73,9 +73,9 @@ class CreateProjectFolders(BaseAction): project_entity = self.get_project_from_entity(entities[0]) # Load settings for project project_name = project_entity["full_name"] - get_project_settings = get_project_settings(project_name) + project_settings = get_project_settings(project_name) project_folder_structure = ( - get_project_settings["global"]["project_folder_structure"] + project_settings["global"]["project_folder_structure"] ) if not project_folder_structure: return { diff --git a/pype/modules/ftrack/events/event_user_assigment.py b/pype/modules/ftrack/events/event_user_assigment.py index f65c2334b0..9b0dfe84d1 100644 --- a/pype/modules/ftrack/events/event_user_assigment.py +++ b/pype/modules/ftrack/events/event_user_assigment.py @@ -200,9 +200,9 @@ class UserAssigmentEvent(BaseEvent): project_name = task_entity["project"]["full_name"] project_data = tmp_by_project_name.get(project_name) or {} if "scripts_by_action" not in project_data: - get_project_settings = get_project_settings(project_name) + project_settings = get_project_settings(project_name) _settings = ( - get_project_settings["ftrack"]["events"]["user_assignment"] + project_settings["ftrack"]["events"]["user_assignment"] ) project_data["scripts_by_action"] = _settings.get("scripts") tmp_by_project_name[project_name] = project_data diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index 39384e996e..0ea72be1cb 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -52,12 +52,11 @@ class VersionToTaskStatus(BaseEvent): project_entity = self.get_project_from_entity(task) project_name = project_entity["full_name"] - get_project_settings = get_project_settings(project_name) + project_settings = get_project_settings(project_name) # Load status mapping from presets status_mapping = ( - get_project_settings["ftrack"]["event"]["status_version_to_task"] - ) + project_settings["ftrack"]["events"]["status_version_to_task"]) # Skip if mapping is empty if not status_mapping: continue diff --git a/pype/plugins/maya/publish/extract_camera_mayaScene.py b/pype/plugins/maya/publish/extract_camera_mayaScene.py index a01c5885b0..0443357ba9 100644 --- a/pype/plugins/maya/publish/extract_camera_mayaScene.py +++ b/pype/plugins/maya/publish/extract_camera_mayaScene.py @@ -102,8 +102,8 @@ class ExtractCameraMayaScene(pype.api.Extractor): def process(self, instance): """Plugin entry point.""" # get settings - # TODO: load all settings directly, rather than passing them through context - ext_mapping = instance.context.data["presets"]["maya"].get("ext_mapping") # noqa: E501 + ext_mapping = (instance.context.data["presets"]["maya"] + .get("ext_mapping")) # noqa: E501 if ext_mapping: self.log.info("Looking in presets for scene type ...") # use extension mapping for first family found diff --git a/pype/plugins/maya/publish/submit_maya_muster.py b/pype/plugins/maya/publish/submit_maya_muster.py index 65889bf068..9c67b45721 100644 --- a/pype/plugins/maya/publish/submit_maya_muster.py +++ b/pype/plugins/maya/publish/submit_maya_muster.py @@ -27,7 +27,8 @@ def _get_template_id(renderer): templates = get_system_settings()["modules"]["Muster"]["templates_mapping"] if not templates: - raise RuntimeError(("Muster template mapping missing in pype-settings")) + raise RuntimeError(("Muster template mapping missing in " + "pype-settings")) try: template_id = templates[renderer] except KeyError: diff --git a/setup/maya/userSetup.py b/setup/maya/userSetup.py index e401580bd8..6ee008c5fc 100644 --- a/setup/maya/userSetup.py +++ b/setup/maya/userSetup.py @@ -14,7 +14,8 @@ shelf_preset = settings['maya'].get('project_shelf') if shelf_preset: project = os.environ["AVALON_PROJECT"] - icon_path = os.path.join(os.environ['PYPE_PROJECT_SCRIPTS'], project, "icons") + icon_path = os.path.join(os.environ['PYPE_PROJECT_SCRIPTS'], + project, "icons") icon_path = os.path.abspath(icon_path) for i in shelf_preset['imports']: From 372569c5b1c3d126f2f2b3aa99ea903607534ffd Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Dec 2020 22:02:14 +0100 Subject: [PATCH 271/279] fix imports and usage of get_anatomy_settings --- pype/api.py | 4 ++-- pype/modules/ftrack/lib/avalon_sync.py | 4 ++-- pype/settings/lib.py | 5 ++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/pype/api.py b/pype/api.py index 3854da6d30..8bf6a9b4b3 100644 --- a/pype/api.py +++ b/pype/api.py @@ -2,7 +2,7 @@ from .settings import ( get_system_settings, get_project_settings, get_current_project_settings, - get_anatomy_data, + get_anatomy_settings, get_environments ) from pypeapp import ( @@ -55,7 +55,7 @@ __all__ = [ "get_system_settings", "get_project_settings", "get_current_project_settings", - "get_anatomy_data", + "get_anatomy_settings", "get_environments", "Logger", diff --git a/pype/modules/ftrack/lib/avalon_sync.py b/pype/modules/ftrack/lib/avalon_sync.py index 0716a5975f..cb34ce918d 100644 --- a/pype/modules/ftrack/lib/avalon_sync.py +++ b/pype/modules/ftrack/lib/avalon_sync.py @@ -8,7 +8,7 @@ import copy from avalon.api import AvalonMongoDB import avalon -from pype.api import Logger, Anatomy, get_anatomy_data +from pype.api import Logger, Anatomy, get_anatomy_settings from bson.objectid import ObjectId from bson.errors import InvalidId @@ -1096,7 +1096,7 @@ class SyncEntitiesFactory: def prepare_ftrack_ent_data(self): project_name = self.entities_dict[self.ft_project_id]["name"] - project_anatomy_data = get_anatomy_data(project_name) + project_anatomy_data = get_anatomy_settings(project_name) task_type_mapping = ( project_anatomy_data["attributes"]["task_short_names"] diff --git a/pype/settings/lib.py b/pype/settings/lib.py index 60e5f00dba..c8578b84f8 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -440,7 +440,7 @@ def get_default_project_settings(clear_metadata=True): return result -def get_default_anatomy_settings(): +def get_default_anatomy_settings(clear_metadata=True): """Project anatomy data with applied studio's default project overrides.""" default_values = get_default_settings()[PROJECT_ANATOMY_KEY] studio_values = get_studio_project_anatomy_overrides() @@ -450,8 +450,7 @@ def get_default_anatomy_settings(): return result - -def get_anatomy_settings(project_name): +def get_anatomy_settings(project_name, clear_metadata=True): """Project anatomy data with applied studio and project overrides.""" if not project_name: raise ValueError( From 3deca82c818c35b37a0b73cf26f4e0954f38966a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Dec 2020 11:05:47 +0100 Subject: [PATCH 272/279] do not remove metadata from system settings on loading of environments --- pype/settings/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index c8578b84f8..d7395e7f1a 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -510,7 +510,7 @@ def get_environments(): dict: Output should be ready for `acre` module. """ - return find_environments(get_system_settings()) + return find_environments(get_system_settings(False)) def clear_metadata_from_settings(values): From 3e51791e171ad05dc039068c8f90805ec51f8b49 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Dec 2020 11:14:55 +0100 Subject: [PATCH 273/279] fix list item on overrides application --- pype/tools/settings/settings/widgets/item_types.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 063262c43f..5f0b326052 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1744,7 +1744,9 @@ class ListWidget(QtWidgets.QWidget, InputObject): def apply_overrides(self, parent_values): self._is_modified = False - if parent_values is NOT_SET or self.key not in parent_values: + if self.as_widget: + override_value = parent_values + elif parent_values is NOT_SET or self.key not in parent_values: override_value = NOT_SET else: override_value = parent_values[self.key] From 85ed78761e082fa16906a4460b644a9bfc97db75 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Dec 2020 11:15:08 +0100 Subject: [PATCH 274/279] changed order of changes check --- pype/tools/settings/settings/widgets/item_types.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 5f0b326052..d07ed91d8d 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2347,9 +2347,9 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): if self._is_empty: return False return ( - self.is_value_modified() - or self.is_key_modified() + self.is_key_modified() or self.is_key_label_modified() + or self.is_value_modified() ) def hierarchical_style_update(self): From 405d15bc9735836b7419da0152dfe1a71e6b5b73 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Dec 2020 11:42:05 +0100 Subject: [PATCH 275/279] fix style setting --- pype/tools/settings/settings/widgets/item_types.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index d07ed91d8d..d96fb60cdd 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -326,9 +326,11 @@ class SettingObject: return True if self.is_overidable: + if self.as_widget: + return self._was_overriden != self.is_overriden return self.was_overriden != self.is_overriden - else: - return self.has_studio_override != self.had_studio_override + + return self.has_studio_override != self.had_studio_override @property def is_overriden(self): From edfa4589afd853f91429ef161507ee25879513a5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Dec 2020 12:01:58 +0100 Subject: [PATCH 276/279] fix project overrides loading on save --- pype/tools/settings/settings/widgets/base.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index 5127ea9f88..cca4a3b149 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -236,15 +236,12 @@ class SettingsCategoryWidget(QtWidgets.QWidget): self.save() - self._update_values() - def _on_refresh(self): self.reset() def _on_hide_studio_overrides(self, state): self._hide_studio_overrides = (state == QtCore.Qt.Checked) self._update_values() - self.hierarchical_style_update() def _save_as_defaults(self): if not self.items_are_valid(): @@ -288,7 +285,6 @@ class SettingsCategoryWidget(QtWidgets.QWidget): reset_default_settings() self._update_values() - self.hierarchical_style_update() def _update_values(self): self.ignore_value_changes = True @@ -373,6 +369,8 @@ class SystemWidget(SettingsCategoryWidget): save_studio_settings(values) + self._update_values() + def update_values(self): default_values = lib.convert_data_to_gui_data({ self.main_schema_key: get_default_settings()[SYSTEM_SETTINGS_KEY] From 4c866c9669e1adc675966dd8b55bea5b868d47f9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Dec 2020 12:06:31 +0100 Subject: [PATCH 277/279] fix update values properly --- pype/tools/settings/settings/widgets/base.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index cca4a3b149..74ffd8e861 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -236,6 +236,8 @@ class SettingsCategoryWidget(QtWidgets.QWidget): self.save() + self._update_values() + def _on_refresh(self): self.reset() @@ -369,8 +371,6 @@ class SystemWidget(SettingsCategoryWidget): save_studio_settings(values) - self._update_values() - def update_values(self): default_values = lib.convert_data_to_gui_data({ self.main_schema_key: get_default_settings()[SYSTEM_SETTINGS_KEY] @@ -588,14 +588,10 @@ class ProjectWidget(SettingsCategoryWidget): project_anatomy_data = output_data.get(PROJECT_ANATOMY_KEY, {}) save_project_anatomy(self.project_name, project_anatomy_data) - if studio_overrides: - # Update saved values - self._update_values() - else: - # Refill values with overrides - self._on_project_change() - def update_values(self): + if not self.project_name is None: + self._on_project_change() + return default_values = lib.convert_data_to_gui_data( {self.main_schema_key: get_default_settings()} ) From 4be0776d84b1e431bbc96a14f393aff22ee42d47 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Dec 2020 12:12:17 +0100 Subject: [PATCH 278/279] formatting changes --- pype/tools/settings/settings/widgets/base.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index 74ffd8e861..404ef8fed7 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -589,9 +589,10 @@ class ProjectWidget(SettingsCategoryWidget): save_project_anatomy(self.project_name, project_anatomy_data) def update_values(self): - if not self.project_name is None: + if self.project_name is not None: self._on_project_change() return + default_values = lib.convert_data_to_gui_data( {self.main_schema_key: get_default_settings()} ) From 3e6051215008e0a3a76f51c73a393370015e50db Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Fri, 4 Dec 2020 12:32:35 +0100 Subject: [PATCH 279/279] remove adobe communicator --- pype/modules/adobe_communicator/__init__.py | 5 - .../adobe_communicator/adobe_comunicator.py | 49 -------- .../adobe_communicator/lib/__init__.py | 6 - .../modules/adobe_communicator/lib/publish.py | 57 --------- .../adobe_communicator/lib/rest_api.py | 117 ------------------ 5 files changed, 234 deletions(-) delete mode 100644 pype/modules/adobe_communicator/__init__.py delete mode 100644 pype/modules/adobe_communicator/adobe_comunicator.py delete mode 100644 pype/modules/adobe_communicator/lib/__init__.py delete mode 100644 pype/modules/adobe_communicator/lib/publish.py delete mode 100644 pype/modules/adobe_communicator/lib/rest_api.py diff --git a/pype/modules/adobe_communicator/__init__.py b/pype/modules/adobe_communicator/__init__.py deleted file mode 100644 index 4110ab69b5..0000000000 --- a/pype/modules/adobe_communicator/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from .adobe_comunicator import AdobeCommunicator - - -def tray_init(tray_widget, main_widget): - return AdobeCommunicator() diff --git a/pype/modules/adobe_communicator/adobe_comunicator.py b/pype/modules/adobe_communicator/adobe_comunicator.py deleted file mode 100644 index 51cc6780c0..0000000000 --- a/pype/modules/adobe_communicator/adobe_comunicator.py +++ /dev/null @@ -1,49 +0,0 @@ -import os -import pype -from pype.api import Logger -from .lib import AdobeRestApi, PUBLISH_PATHS - -log = Logger().get_logger("AdobeCommunicator") - - -class AdobeCommunicator: - rest_api_obj = None - - def __init__(self): - self.rest_api_obj = None - - # Add "adobecommunicator" publish paths - PUBLISH_PATHS.append(os.path.sep.join( - [pype.PLUGINS_DIR, "adobecommunicator", "publish"] - )) - - def tray_start(self): - return - - def process_modules(self, modules): - # Module requires RestApiServer - rest_api_module = modules.get("RestApiServer") - if not rest_api_module: - log.warning( - "AdobeCommunicator won't work without RestApiServer." - ) - return - - # Register statics url - pype_module_root = os.environ["PYPE_MODULE_ROOT"].replace("\\", "/") - static_path = "{}/pype/hosts/premiere/ppro".format(pype_module_root) - rest_api_module.register_statics("/ppro", static_path) - - # Register rest api object for communication - self.rest_api_obj = AdobeRestApi() - - # Add Ftrack publish path if registered Ftrack mdule - if "FtrackModule" in modules: - PUBLISH_PATHS.append(os.path.sep.join( - [pype.PLUGINS_DIR, "ftrack", "publish"] - )) - - log.debug(( - f"Adobe Communicator Registered PUBLISH_PATHS" - f"> `{PUBLISH_PATHS}`" - )) diff --git a/pype/modules/adobe_communicator/lib/__init__.py b/pype/modules/adobe_communicator/lib/__init__.py deleted file mode 100644 index f918e49a60..0000000000 --- a/pype/modules/adobe_communicator/lib/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from .rest_api import AdobeRestApi, PUBLISH_PATHS - -__all__ = [ - "PUBLISH_PATHS", - "AdobeRestApi" -] diff --git a/pype/modules/adobe_communicator/lib/publish.py b/pype/modules/adobe_communicator/lib/publish.py deleted file mode 100644 index b222a1bd59..0000000000 --- a/pype/modules/adobe_communicator/lib/publish.py +++ /dev/null @@ -1,57 +0,0 @@ -import os -import sys -import pype -import importlib -import pyblish.api -import pyblish.util -import avalon.api -from avalon.tools import publish -from pype.api import Logger - -log = Logger().get_logger(__name__) - - -def main(env): - # Registers pype's Global pyblish plugins - pype.install() - - # Register Host (and it's pyblish plugins) - host_name = env["AVALON_APP"] - # TODO not sure if use "pype." or "avalon." for host import - host_import_str = f"pype.hosts.{host_name}" - - try: - host_module = importlib.import_module(host_import_str) - except ModuleNotFoundError: - log.error(( - f"Host \"{host_name}\" can't be imported." - f" Import string \"{host_import_str}\" failed." - )) - return False - - avalon.api.install(host_module) - - # Register additional paths - addition_paths_str = env.get("PUBLISH_PATHS") or "" - addition_paths = addition_paths_str.split(os.pathsep) - for path in addition_paths: - path = os.path.normpath(path) - if not os.path.exists(path): - continue - - pyblish.api.register_plugin_path(path) - - # Register project specific plugins - project_name = os.environ["AVALON_PROJECT"] - project_plugins_paths = env.get("PYPE_PROJECT_PLUGINS") or "" - for path in project_plugins_paths.split(os.pathsep): - plugin_path = os.path.join(path, project_name, "plugins") - if os.path.exists(plugin_path): - pyblish.api.register_plugin_path(plugin_path) - - return publish.show() - - -if __name__ == "__main__": - result = main(os.environ) - sys.exit(not bool(result)) diff --git a/pype/modules/adobe_communicator/lib/rest_api.py b/pype/modules/adobe_communicator/lib/rest_api.py deleted file mode 100644 index 35094d10dc..0000000000 --- a/pype/modules/adobe_communicator/lib/rest_api.py +++ /dev/null @@ -1,117 +0,0 @@ -import os -import sys -import copy -from pype.modules.rest_api import RestApi, route, abort, CallbackResult -from avalon.api import AvalonMongoDB -from pype.api import config, execute, Logger - -log = Logger().get_logger("AdobeCommunicator") - -CURRENT_DIR = os.path.dirname(__file__) -PUBLISH_SCRIPT_PATH = os.path.join(CURRENT_DIR, "publish.py") - -PUBLISH_PATHS = [] - - -class AdobeRestApi(RestApi): - dbcon = AvalonMongoDB() - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.dbcon.install() - - @route("/available", "/adobe") - def available(self): - return CallbackResult() - - @route("/presets/", "/adobe") - def get_presets(self, request): - project_name = request.url_data["project_name"] - return CallbackResult(data=config.get_presets(project_name)) - - @route("/publish", "/adobe", "POST") - def publish(self, request): - """Triggers publishing script in subprocess. - - The subprocess freeze process and during publishing is not possible to - handle other requests and is possible that freeze main application. - - TODO: Freezing issue may be fixed with socket communication. - - Example url: - http://localhost:8021/adobe/publish (POST) - """ - try: - publish_env = self._prepare_publish_environments( - request.request_data - ) - except Exception as exc: - log.warning( - "Failed to prepare environments for publishing.", - exc_info=True - ) - abort(400, str(exc)) - - output_data_path = publish_env["AC_PUBLISH_OUTPATH"] - - log.info("Pyblish is running") - try: - # Trigger subprocess - # QUESTION should we check returncode? - returncode = execute( - [sys.executable, PUBLISH_SCRIPT_PATH], - env=publish_env - ) - - # Check if output file exists - if returncode != 0 or not os.path.exists(output_data_path): - abort(500, "Publishing failed") - - log.info("Pyblish have stopped") - - return CallbackResult( - data={"return_data_path": output_data_path} - ) - - except Exception: - log.warning("Publishing failed", exc_info=True) - abort(500, "Publishing failed") - - def _prepare_publish_environments(self, data): - """Prepares environments based on request data.""" - env = copy.deepcopy(os.environ) - - project_name = data["project"] - asset_name = data["asset"] - - project_doc = self.dbcon[project_name].find_one({ - "type": "project" - }) - av_asset = self.dbcon[project_name].find_one({ - "type": "asset", - "name": asset_name - }) - parents = av_asset["data"]["parents"] - hierarchy = "" - if parents: - hierarchy = "/".join(parents) - - env["AVALON_PROJECT"] = project_name - env["AVALON_ASSET"] = asset_name - env["AVALON_TASK"] = data["task"] - env["AVALON_WORKDIR"] = data["workdir"] - env["AVALON_HIERARCHY"] = hierarchy - env["AVALON_PROJECTCODE"] = project_doc["data"].get("code", "") - env["AVALON_APP"] = data["AVALON_APP"] - env["AVALON_APP_NAME"] = data["AVALON_APP_NAME"] - - env["PYBLISH_HOSTS"] = data["AVALON_APP"] - - env["PUBLISH_PATHS"] = os.pathsep.join(PUBLISH_PATHS) - - # Input and Output paths where source data and result data will be - # stored - env["AC_PUBLISH_INPATH"] = data["adobePublishJsonPathSend"] - env["AC_PUBLISH_OUTPATH"] = data["adobePublishJsonPathGet"] - - return env