From b1af13250859360d0f36258371914d0df15d8c58 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 8 Oct 2020 11:07:17 +0200 Subject: [PATCH 01/11] fix(nks): order of plugin, fix(nuke): typo in namespace --- pype/hosts/nuke/lib.py | 6 +++--- .../plugins/nukestudio/publish/collect_hierarchy_context.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pype/hosts/nuke/lib.py b/pype/hosts/nuke/lib.py index 8c0e37b15d..7c5a48c100 100644 --- a/pype/hosts/nuke/lib.py +++ b/pype/hosts/nuke/lib.py @@ -1065,7 +1065,7 @@ class BuildWorkfile(WorkfileSettings): Building first version of workfile. Settings are taken from presets and db. It will add all subsets - in last version for defined representaions + in last version for defined representations Arguments: variable (type): description @@ -1233,7 +1233,7 @@ class BuildWorkfile(WorkfileSettings): log.info("Building Loader to: `{}`".format(name)) version = subset["version"] log.info("Version to: `{}`".format(version["name"])) - representations = subset["representaions"] + representations = subset["representations"] for repr in representations: rn = self.read_loader(repr) rn["xpos"].setValue(self.xpos) @@ -1247,7 +1247,7 @@ class BuildWorkfile(WorkfileSettings): if len(lut_subset) > 0: lsub = lut_subset[0] - fxn = self.effect_loader(lsub["representaions"][-1]) + fxn = self.effect_loader(lsub["representations"][-1]) fxn_ypos = fxn["ypos"].value() fxn["ypos"].setValue(fxn_ypos - 100) nodes_backdrop.append(fxn) diff --git a/pype/plugins/nukestudio/publish/collect_hierarchy_context.py b/pype/plugins/nukestudio/publish/collect_hierarchy_context.py index a41e987bdb..4fc02a4b3d 100644 --- a/pype/plugins/nukestudio/publish/collect_hierarchy_context.py +++ b/pype/plugins/nukestudio/publish/collect_hierarchy_context.py @@ -13,7 +13,7 @@ class CollectHierarchyInstance(pyblish.api.ContextPlugin): """ label = "Collect Hierarchy Clip" - order = pyblish.api.CollectorOrder + 0.101 + order = pyblish.api.CollectorOrder + 0.102 families = ["clip"] def convert_to_entity(self, key, value): From c2fcfd0aaf92fc9090694dd031d2edf241761448 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 8 Oct 2020 12:52:55 +0200 Subject: [PATCH 02/11] fix(nks): preview to review tag on representation order of hierarchy context was wrong --- pype/plugins/nukestudio/publish/collect_hierarchy_context.py | 2 +- pype/plugins/nukestudio/publish/collect_plates.py | 2 +- pype/plugins/nukestudio/publish/collect_reviews.py | 2 +- pype/plugins/nukestudio/publish/extract_review_cutup_video.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pype/plugins/nukestudio/publish/collect_hierarchy_context.py b/pype/plugins/nukestudio/publish/collect_hierarchy_context.py index 4fc02a4b3d..fddda72635 100644 --- a/pype/plugins/nukestudio/publish/collect_hierarchy_context.py +++ b/pype/plugins/nukestudio/publish/collect_hierarchy_context.py @@ -217,7 +217,7 @@ class CollectHierarchyContext(pyblish.api.ContextPlugin): ''' label = "Collect Hierarchy Context" - order = pyblish.api.CollectorOrder + 0.102 + order = pyblish.api.CollectorOrder + 0.103 def update_dict(self, ex_dict, new_dict): for key in ex_dict: diff --git a/pype/plugins/nukestudio/publish/collect_plates.py b/pype/plugins/nukestudio/publish/collect_plates.py index 770cef7e3f..44109716bb 100644 --- a/pype/plugins/nukestudio/publish/collect_plates.py +++ b/pype/plugins/nukestudio/publish/collect_plates.py @@ -183,7 +183,7 @@ class CollectPlatesData(api.InstancePlugin): "frameEnd": instance.data["sourceOut"] - instance.data["sourceIn"] + 1, 'step': 1, 'fps': instance.context.data["fps"], - 'tags': ["preview"], + 'tags': ["review"], 'name': "preview", 'ext': "mov", } diff --git a/pype/plugins/nukestudio/publish/collect_reviews.py b/pype/plugins/nukestudio/publish/collect_reviews.py index aa8c60767c..8fdcd666bc 100644 --- a/pype/plugins/nukestudio/publish/collect_reviews.py +++ b/pype/plugins/nukestudio/publish/collect_reviews.py @@ -99,7 +99,7 @@ class CollectReviews(api.InstancePlugin): "step": 1, "fps": rev_inst.data.get("fps"), "name": "preview", - "tags": ["preview"], + "tags": ["review"], "ext": ext } diff --git a/pype/plugins/nukestudio/publish/extract_review_cutup_video.py b/pype/plugins/nukestudio/publish/extract_review_cutup_video.py index d1ce3675b1..4776a282be 100644 --- a/pype/plugins/nukestudio/publish/extract_review_cutup_video.py +++ b/pype/plugins/nukestudio/publish/extract_review_cutup_video.py @@ -227,7 +227,7 @@ class ExtractReviewCutUpVideo(pype.api.Extractor): "step": 1, "fps": fps, "name": "cut_up_preview", - "tags": ["review", "delete"] + self.tags_addition, + "tags": ["review"] + self.tags_addition, "ext": ext, "anatomy_template": "publish" } From cdec4d9281593cd2e66b0f6144b349c1d8012dc0 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 8 Oct 2020 15:00:55 +0200 Subject: [PATCH 03/11] fps(nks): fps collecting into clip instances --- pype/plugins/nukestudio/publish/collect_clips.py | 6 ++++-- pype/plugins/nukestudio/publish/collect_framerate.py | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/pype/plugins/nukestudio/publish/collect_clips.py b/pype/plugins/nukestudio/publish/collect_clips.py index d39e25bfc6..40b197897c 100644 --- a/pype/plugins/nukestudio/publish/collect_clips.py +++ b/pype/plugins/nukestudio/publish/collect_clips.py @@ -1,9 +1,9 @@ import os - from pyblish import api import hiero import nuke + class CollectClips(api.ContextPlugin): """Collect all Track items selection.""" @@ -144,7 +144,9 @@ class CollectClips(api.ContextPlugin): "family": "clip", "families": [], "handleStart": projectdata.get("handleStart", 0), - "handleEnd": projectdata.get("handleEnd", 0)}) + "handleEnd": projectdata.get("handleEnd", 0), + "fps": context.data["fps"] + }) instance = context.create_instance(**data) diff --git a/pype/plugins/nukestudio/publish/collect_framerate.py b/pype/plugins/nukestudio/publish/collect_framerate.py index 694052f802..cb3c9f215f 100644 --- a/pype/plugins/nukestudio/publish/collect_framerate.py +++ b/pype/plugins/nukestudio/publish/collect_framerate.py @@ -4,13 +4,14 @@ from pyblish import api class CollectFramerate(api.ContextPlugin): """Collect framerate from selected sequence.""" - order = api.CollectorOrder + 0.01 + order = api.CollectorOrder + 0.001 label = "Collect Framerate" hosts = ["nukestudio"] def process(self, context): sequence = context.data["activeSequence"] context.data["fps"] = self.get_rate(sequence) + self.log.info("Framerate is collected: {}".format(context.data["fps"])) def get_rate(self, sequence): num, den = sequence.framerate().toRational() From cf0d2f2adc23ec8476617ecd3b0b7f8b98ac900f Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 8 Oct 2020 15:54:00 +0200 Subject: [PATCH 04/11] bump version --- pype/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/version.py b/pype/version.py index 521faacafe..896b89678f 100644 --- a/pype/version.py +++ b/pype/version.py @@ -1 +1 @@ -__version__ = "2.12.3" +__version__ = "2.12.4" From 1774c76d62d4013d6ef13a07396dbfd09a88c25f Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Wed, 14 Oct 2020 15:02:24 +0200 Subject: [PATCH 05/11] disable application launch logic --- pype/hosts/harmony/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pype/hosts/harmony/__init__.py b/pype/hosts/harmony/__init__.py index fbf5ca6f12..910b7ab6ab 100644 --- a/pype/hosts/harmony/__init__.py +++ b/pype/hosts/harmony/__init__.py @@ -155,8 +155,10 @@ def check_inventory(): def application_launch(): - ensure_scene_settings() - check_inventory() + # FIXME: manually invoked because of server <-> client problems. + # ensure_scene_settings() + # check_inventory() + pass def export_template(backdrops, nodes, filepath): From f99bccd6215cd269e5e76d0a38d63ac778056afc Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Wed, 14 Oct 2020 17:17:14 +0200 Subject: [PATCH 06/11] bump version --- pype/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/version.py b/pype/version.py index 896b89678f..336282f43c 100644 --- a/pype/version.py +++ b/pype/version.py @@ -1 +1 @@ -__version__ = "2.12.4" +__version__ = "2.12.5" From 8c7e871e8ad497617d2c74f95f3e8c584b997aae Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Fri, 16 Oct 2020 15:46:53 +0200 Subject: [PATCH 07/11] Create weekly-digest.yml --- .github/weekly-digest.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .github/weekly-digest.yml diff --git a/.github/weekly-digest.yml b/.github/weekly-digest.yml new file mode 100644 index 0000000000..fe502fbc98 --- /dev/null +++ b/.github/weekly-digest.yml @@ -0,0 +1,7 @@ +# Configuration for weekly-digest - https://github.com/apps/weekly-digest +publishDay: sun +canPublishIssues: true +canPublishPullRequests: true +canPublishContributors: true +canPublishStargazers: true +canPublishCommits: true From 1ba4bc5a3b3c795e0f7a3a4f1c08c0b9b194f4e9 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Sat, 17 Oct 2020 00:22:51 +0200 Subject: [PATCH 08/11] bump version --- pype/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/version.py b/pype/version.py index 336282f43c..930e2cd686 100644 --- a/pype/version.py +++ b/pype/version.py @@ -1 +1 @@ -__version__ = "2.12.5" +__version__ = "2.13.0" From 987a06dddab88f1ec713a37d08556faee9b30f31 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Sun, 18 Oct 2020 23:07:25 +0200 Subject: [PATCH 09/11] update changelog --- CHANGELOG.md | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 158 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba86b85eec..5b39d09327 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,155 @@ # Changelog -## [2.12.0](https://github.com/pypeclub/pype/tree/2.12.0) (2020-09-09) +## [2.13.0](https://github.com/pypeclub/pype/tree/2.13.0) (2020-10-16) + +[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) @@ -16,9 +165,7 @@ - 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) -- ftrack group is bcw compatible [\#418](https://github.com/pypeclub/pype/pull/418) - 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:** @@ -123,6 +270,14 @@ [Full Changelog](https://github.com/pypeclub/pype/compare/2.11.0...2.11.1) +**Enhancements:** + +- Feature/little bit better logging gui [\#383](https://github.com/pypeclub/pype/pull/383) + +**Fixed bugs:** + +- celaction deadline rendering [\#378](https://github.com/pypeclub/pype/pull/378) + **Merged pull requests:** - Celaction: metadata json folder fixes on path [\#393](https://github.com/pypeclub/pype/pull/393) From abc70685fa05bacf6c51ed5593041ecfa40f2616 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 22 Oct 2020 14:54:16 +0200 Subject: [PATCH 10/11] fix(hiero): cutup source audio video clip differently then nonaudio one frame difference issue --- pype/plugins/hiero/publish/extract_review_cutup.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pype/plugins/hiero/publish/extract_review_cutup.py b/pype/plugins/hiero/publish/extract_review_cutup.py index 57ec6c1107..88b19b7ec8 100644 --- a/pype/plugins/hiero/publish/extract_review_cutup.py +++ b/pype/plugins/hiero/publish/extract_review_cutup.py @@ -133,14 +133,24 @@ class ExtractReviewCutUp(pype.api.Extractor): "{ffprobe_path} -i \"{full_input_path}\" -show_streams " "-select_streams a -loglevel error" ).format(**locals()) + self.log.debug("ffprob_cmd: {}".format(ffprob_cmd)) audio_check_output = pype.api.subprocess(ffprob_cmd) self.log.debug( "audio_check_output: {}".format(audio_check_output)) + # Fix one frame difference + """ TODO: this is just work-around for issue: + https://github.com/pypeclub/pype/issues/659 + """ + frame_duration_extend = 1 + if audio_check_output: + frame_duration_extend = 0 + # translate frame to sec start_sec = float(frame_start) / fps - duration_sec = float(frame_end - frame_start + 1) / fps + duration_sec = float( + (frame_end - frame_start) + frame_duration_extend) / fps empty_add = None From 13c14b8a86bbfd0b98fedf1dfa943aaa65358aa2 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Fri, 23 Oct 2020 12:52:38 +0200 Subject: [PATCH 11/11] cherry picked #654 - Fix Layer name is not propagating --- .../stubs/photoshop_server_stub.py | 102 +++++++++++------- pype/plugins/photoshop/load/load_image.py | 54 +++++++++- 2 files changed, 114 insertions(+), 42 deletions(-) diff --git a/pype/modules/websocket_server/stubs/photoshop_server_stub.py b/pype/modules/websocket_server/stubs/photoshop_server_stub.py index da69127799..04fb7eff0f 100644 --- a/pype/modules/websocket_server/stubs/photoshop_server_stub.py +++ b/pype/modules/websocket_server/stubs/photoshop_server_stub.py @@ -22,8 +22,9 @@ class PhotoshopServerStub(): def open(self, path): """ Open file located at 'path' (local). - :param path: file path locally - :return: None + Args: + path(string): file path locally + Returns: None """ self.websocketserver.call(self.client.call ('Photoshop.open', path=path) @@ -32,9 +33,10 @@ class PhotoshopServerStub(): def read(self, layer, layers_meta=None): """ Parses layer metadata from Headline field of active document - :param layer: Layer("id": XXX, "name":'YYY') - :param data: json representation for single layer - :param all_layers: - for performance, could be + Args: + layer (namedtuple): Layer("id": XXX, "name":'YYY') + data(string): json representation for single layer + all_layers (list of namedtuples): for performance, could be injected for usage in loop, if not, single call will be triggered - :param layers_meta: json representation from Headline + layers_meta(string): json representation from Headline (for performance - provide only if imprint is in loop - value should be same) - :return: None + Returns: None """ if not layers_meta: layers_meta = self.get_layers_metadata() # json.dumps writes integer values in a dictionary to string, so # anticipating it here. if str(layer.id) in layers_meta and layers_meta[str(layer.id)]: - layers_meta[str(layer.id)].update(data) + if data: + layers_meta[str(layer.id)].update(data) + else: + layers_meta.pop(str(layer.id)) else: layers_meta[str(layer.id)] = data @@ -83,7 +89,7 @@ class PhotoshopServerStub(): """ Returns JSON document with all(?) layers in active document. - :return: + Returns: Format of tuple: { 'id':'123', 'name': 'My Layer 1', 'type': 'GUIDE'|'FG'|'BG'|'OBJ' @@ -97,8 +103,9 @@ class PhotoshopServerStub(): def get_layers_in_layers(self, layers): """ Return all layers that belong to layers (might be groups). - :param layers: - :return: + Args: + layers : + Returns: """ all_layers = self.get_layers() ret = [] @@ -116,7 +123,7 @@ class PhotoshopServerStub(): def create_group(self, name): """ Create new group (eg. LayerSet) - :return: + Returns: """ ret = self.websocketserver.call(self.client.call ('Photoshop.create_group', @@ -128,7 +135,7 @@ class PhotoshopServerStub(): def group_selected_layers(self, name): """ Group selected layers into new LayerSet (eg. group) - :return: + Returns: """ res = self.websocketserver.call(self.client.call ('Photoshop.group_selected_layers', @@ -139,7 +146,7 @@ class PhotoshopServerStub(): def get_selected_layers(self): """ Get a list of actually selected layers - :return: + Returns: """ res = self.websocketserver.call(self.client.call ('Photoshop.get_selected_layers')) @@ -147,9 +154,10 @@ class PhotoshopServerStub(): def select_layers(self, layers): """ - Selecte specified layers in Photoshop - :param layers: - :return: None + Selects specified layers in Photoshop by its ids + Args: + layers: + Returns: None """ layer_ids = [layer.id for layer in layers] @@ -161,7 +169,7 @@ class PhotoshopServerStub(): def get_active_document_full_name(self): """ Returns full name with path of active document via ws call - :return: full path with name + Returns(string): full path with name """ res = self.websocketserver.call( self.client.call('Photoshop.get_active_document_full_name')) @@ -171,7 +179,7 @@ class PhotoshopServerStub(): def get_active_document_name(self): """ Returns just a name of active document via ws call - :return: file name + Returns(string): file name """ res = self.websocketserver.call(self.client.call ('Photoshop.get_active_document_name')) @@ -181,7 +189,7 @@ class PhotoshopServerStub(): def is_saved(self): """ Returns true if no changes in active document - :return: + Returns: """ return self.websocketserver.call(self.client.call ('Photoshop.is_saved')) @@ -189,7 +197,7 @@ class PhotoshopServerStub(): def save(self): """ Saves active document - :return: None + Returns: None """ self.websocketserver.call(self.client.call ('Photoshop.save')) @@ -197,10 +205,11 @@ class PhotoshopServerStub(): def saveAs(self, image_path, ext, as_copy): """ Saves active document to psd (copy) or png or jpg - :param image_path: full local path - :param ext: - :param as_copy: - :return: None + Args: + image_path(string): full local path + ext: + as_copy: + Returns: None """ self.websocketserver.call(self.client.call ('Photoshop.saveAs', @@ -211,9 +220,10 @@ class PhotoshopServerStub(): def set_visible(self, layer_id, visibility): """ Set layer with 'layer_id' to 'visibility' - :param layer_id: - :param visibility: - :return: None + Args: + layer_id: + visibility: + Returns: None """ self.websocketserver.call(self.client.call ('Photoshop.set_visible', @@ -224,7 +234,7 @@ class PhotoshopServerStub(): """ Reads layers metadata from Headline from active document in PS. (Headline accessible by File > File Info) - :return: - json documents + Returns(string): - json documents """ layers_data = {} res = self.websocketserver.call(self.client.call('Photoshop.read')) @@ -234,22 +244,26 @@ class PhotoshopServerStub(): pass return layers_data - def import_smart_object(self, path): + def import_smart_object(self, path, layer_name): """ Import the file at `path` as a smart object to active document. Args: path (str): File path to import. + layer_name (str): Unique layer name to differentiate how many times + same smart object was loaded """ res = self.websocketserver.call(self.client.call ('Photoshop.import_smart_object', - path=path)) + path=path, name=layer_name)) return self._to_records(res).pop() - def replace_smart_object(self, layer, path): + def replace_smart_object(self, layer, path, layer_name): """ Replace the smart object `layer` with file at `path` + layer_name (str): Unique layer name to differentiate how many times + same smart object was loaded Args: layer (namedTuple): Layer("id":XX, "name":"YY"..). @@ -257,8 +271,18 @@ class PhotoshopServerStub(): """ self.websocketserver.call(self.client.call ('Photoshop.replace_smart_object', - layer=layer, - path=path)) + layer_id=layer.id, + path=path, name=layer_name)) + + def delete_layer(self, layer_id): + """ + Deletes specific layer by it's id. + Args: + layer_id (int): id of layer to delete + """ + self.websocketserver.call(self.client.call + ('Photoshop.delete_layer', + layer_id=layer_id)) def close(self): self.client.close() @@ -267,8 +291,8 @@ class PhotoshopServerStub(): """ Converts string json representation into list of named tuples for dot notation access to work. - :return: - :param res: - json representation + Returns: + res(string): - json representation """ try: layers_data = json.loads(res) diff --git a/pype/plugins/photoshop/load/load_image.py b/pype/plugins/photoshop/load/load_image.py index 75c02bb327..301e60fbb1 100644 --- a/pype/plugins/photoshop/load/load_image.py +++ b/pype/plugins/photoshop/load/load_image.py @@ -1,4 +1,6 @@ from avalon import api, photoshop +import os +import re stub = photoshop.stub() @@ -13,10 +15,13 @@ class ImageLoader(api.Loader): representations = ["*"] def load(self, context, name=None, namespace=None, data=None): + layer_name = self._get_unique_layer_name(context["asset"]["name"], + name) with photoshop.maintained_selection(): - layer = stub.import_smart_object(self.fname) + layer = stub.import_smart_object(self.fname, layer_name) self[:] = [layer] + namespace = namespace or layer_name return photoshop.containerise( name, @@ -27,11 +32,25 @@ class ImageLoader(api.Loader): ) def update(self, container, representation): + """ Switch asset or change version """ layer = container.pop("layer") + context = representation.get("context", {}) + + namespace_from_container = re.sub(r'_\d{3}$', '', + container["namespace"]) + layer_name = "{}_{}".format(context["asset"], context["subset"]) + # switching assets + if namespace_from_container != layer_name: + layer_name = self._get_unique_layer_name(context["asset"], + context["subset"]) + else: # switching version - keep same name + layer_name = container["namespace"] + + path = api.get_representation_path(representation) with photoshop.maintained_selection(): stub.replace_smart_object( - layer, api.get_representation_path(representation) + layer, path, layer_name ) stub.imprint( @@ -39,7 +58,36 @@ class ImageLoader(api.Loader): ) def remove(self, container): - container["layer"].Delete() + """ + Removes element from scene: deletes layer + removes from Headline + Args: + container (dict): container to be removed - used to get layer_id + """ + layer = container.pop("layer") + stub.imprint(layer, {}) + stub.delete_layer(layer.id) def switch(self, container, representation): self.update(container, representation) + + def _get_unique_layer_name(self, asset_name, subset_name): + """ + Gets all layer names and if 'name' is present in them, increases + suffix by 1 (eg. creates unique layer name - for Loader) + Args: + name (string): in format asset_subset + + Returns: + (string): name_00X (without version) + """ + name = "{}_{}".format(asset_name, subset_name) + names = {} + for layer in stub.get_layers(): + layer_name = re.sub(r'_\d{3}$', '', layer.name) + if layer_name in names.keys(): + names[layer_name] = names[layer_name] + 1 + else: + names[layer_name] = 1 + occurrences = names.get(name, 0) + + return "{}_{:0>3d}".format(name, occurrences + 1)