diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..07c1c151ce --- /dev/null +++ b/.dockerignore @@ -0,0 +1,146 @@ +# Created by .ignore support plugin (hsz.mobi) +### Python template +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +.poetry/ +.github/ +vendor/bin/ +docs/ +website/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..2d8ed27b15 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,82 @@ +# Build Pype docker image +FROM centos:7 AS builder +ARG OPENPYPE_PYTHON_VERSION=3.7.10 + +LABEL org.opencontainers.image.name="pypeclub/openpype" +LABEL org.opencontainers.image.title="OpenPype Docker Image" +LABEL org.opencontainers.image.url="https://openpype.io/" +LABEL org.opencontainers.image.source="https://github.com/pypeclub/pype" + +USER root + +# update base +RUN yum -y install deltarpm \ + && yum -y update \ + && yum clean all + +# add tools we need +RUN yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \ + && yum -y install centos-release-scl \ + && yum -y install \ + bash \ + which \ + git \ + devtoolset-7-gcc* \ + make \ + cmake \ + curl \ + wget \ + gcc \ + zlib-devel \ + bzip2 \ + bzip2-devel \ + readline-devel \ + sqlite sqlite-devel \ + openssl-devel \ + tk-devel libffi-devel \ + qt5-qtbase-devel \ + patchelf \ + && yum clean all + +RUN mkdir /opt/openpype +# RUN useradd -m pype +# RUN chown pype /opt/openpype +# USER pype + +RUN curl https://pyenv.run | bash +ENV PYTHON_CONFIGURE_OPTS --enable-shared + +RUN echo 'export PATH="$HOME/.pyenv/bin:$PATH"'>> $HOME/.bashrc \ + && echo 'eval "$(pyenv init -)"' >> $HOME/.bashrc \ + && echo 'eval "$(pyenv virtualenv-init -)"' >> $HOME/.bashrc \ + && echo 'eval "$(pyenv init --path)"' >> $HOME/.bashrc +RUN source $HOME/.bashrc && pyenv install ${OPENPYPE_PYTHON_VERSION} + +COPY . /opt/openpype/ +RUN rm -rf /openpype/.poetry || echo "No Poetry installed yet." +# USER root +# RUN chown -R pype /opt/openpype +RUN chmod +x /opt/openpype/tools/create_env.sh && chmod +x /opt/openpype/tools/build.sh + +# USER pype + +WORKDIR /opt/openpype + +RUN cd /opt/openpype \ + && source $HOME/.bashrc \ + && pyenv local ${OPENPYPE_PYTHON_VERSION} + +RUN source $HOME/.bashrc \ + && ./tools/create_env.sh + +RUN source $HOME/.bashrc \ + && ./tools/fetch_thirdparty_libs.sh + +RUN source $HOME/.bashrc \ + && bash ./tools/build.sh \ + && cp /usr/lib64/libffi* ./build/exe.linux-x86_64-3.7/lib \ + && cp /usr/lib64/libssl* ./build/exe.linux-x86_64-3.7/lib \ + && cp /usr/lib64/libcrypto* ./build/exe.linux-x86_64-3.7/lib + +RUN cd /opt/openpype \ + rm -rf ./vendor/bin diff --git a/openpype/hosts/aftereffects/api/__init__.py b/openpype/hosts/aftereffects/api/__init__.py index e914c26435..5f6a64a6d0 100644 --- a/openpype/hosts/aftereffects/api/__init__.py +++ b/openpype/hosts/aftereffects/api/__init__.py @@ -112,38 +112,4 @@ def get_asset_settings(): "duration": duration } - try: - # temporary, in pype3 replace with api.get_current_project_settings - skip_resolution_check = ( - api.get_current_project_settings() - ["plugins"] - ["aftereffects"] - ["publish"] - ["ValidateSceneSettings"] - ["skip_resolution_check"] - ) - skip_timelines_check = ( - api.get_current_project_settings() - ["plugins"] - ["aftereffects"] - ["publish"] - ["ValidateSceneSettings"] - ["skip_timelines_check"] - ) - except KeyError: - skip_resolution_check = ['*'] - skip_timelines_check = ['*'] - - if os.getenv('AVALON_TASK') in skip_resolution_check or \ - '*' in skip_timelines_check: - scene_data.pop("resolutionWidth") - scene_data.pop("resolutionHeight") - - if entity_type in skip_timelines_check or '*' in skip_timelines_check: - scene_data.pop('fps', None) - scene_data.pop('frameStart', None) - scene_data.pop('frameEnd', None) - scene_data.pop('handleStart', None) - scene_data.pop('handleEnd', None) - return scene_data diff --git a/openpype/hosts/aftereffects/plugins/publish/validate_scene_settings.py b/openpype/hosts/aftereffects/plugins/publish/validate_scene_settings.py index cc7db3141f..5301a2f3ea 100644 --- a/openpype/hosts/aftereffects/plugins/publish/validate_scene_settings.py +++ b/openpype/hosts/aftereffects/plugins/publish/validate_scene_settings.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- """Validate scene settings.""" import os +import re import pyblish.api @@ -56,13 +57,26 @@ class ValidateSceneSettings(pyblish.api.InstancePlugin): hosts = ["aftereffects"] optional = True - skip_timelines_check = ["*"] # * >> skip for all - skip_resolution_check = ["*"] + skip_timelines_check = [".*"] # * >> skip for all + skip_resolution_check = [".*"] def process(self, instance): """Plugin entry point.""" expected_settings = api.get_asset_settings() - self.log.info("expected_settings::{}".format(expected_settings)) + self.log.info("config from DB::{}".format(expected_settings)) + + if any(re.search(pattern, os.getenv('AVALON_TASK')) + for pattern in self.skip_resolution_check): + expected_settings.pop("resolutionWidth") + expected_settings.pop("resolutionHeight") + + if any(re.search(pattern, os.getenv('AVALON_TASK')) + for pattern in self.skip_timelines_check): + expected_settings.pop('fps', None) + expected_settings.pop('frameStart', None) + expected_settings.pop('frameEnd', None) + expected_settings.pop('handleStart', None) + expected_settings.pop('handleEnd', None) # handle case where ftrack uses only two decimal places # 23.976023976023978 vs. 23.98 @@ -76,6 +90,8 @@ class ValidateSceneSettings(pyblish.api.InstancePlugin): duration = instance.data.get("frameEndHandle") - \ instance.data.get("frameStartHandle") + 1 + self.log.debug("filtered config::{}".format(expected_settings)) + current_settings = { "fps": fps, "frameStartHandle": instance.data.get("frameStartHandle"), diff --git a/openpype/hosts/hiero/otio/utils.py b/openpype/hosts/hiero/otio/utils.py index f882a5d1f2..4c5d46bd51 100644 --- a/openpype/hosts/hiero/otio/utils.py +++ b/openpype/hosts/hiero/otio/utils.py @@ -68,7 +68,11 @@ def get_rate(item): return None num, den = item.framerate().toRational() - rate = float(num) / float(den) + + try: + rate = float(num) / float(den) + except ZeroDivisionError: + return None if rate.is_integer(): return rate diff --git a/openpype/hosts/hiero/plugins/publish/precollect_instances.py b/openpype/hosts/hiero/plugins/publish/precollect_instances.py index a1dee711b7..8cccdec99a 100644 --- a/openpype/hosts/hiero/plugins/publish/precollect_instances.py +++ b/openpype/hosts/hiero/plugins/publish/precollect_instances.py @@ -24,7 +24,7 @@ class PrecollectInstances(pyblish.api.ContextPlugin): for track_item in selected_timeline_items: - data = dict() + data = {} clip_name = track_item.name() # get openpype tag data @@ -43,6 +43,11 @@ class PrecollectInstances(pyblish.api.ContextPlugin): tag_data["handleEnd"] = min( tag_data["handleEnd"], int(track_item.handleOutLength())) + # add audio to families + with_audio = False + if tag_data.pop("audio"): + with_audio = True + # add tag data to instance data data.update({ k: v for k, v in tag_data.items() @@ -94,6 +99,17 @@ class PrecollectInstances(pyblish.api.ContextPlugin): self.log.debug( "_ instance.data: {}".format(pformat(instance.data))) + if not with_audio: + return + + # create audio subset instance + self.create_audio_instance(context, **data) + + # add audioReview attribute to plate instance data + # if reviewTrack is on + if tag_data.get("reviewTrack") is not None: + instance.data["reviewAudio"] = True + def get_resolution_to_data(self, data, context): assert data.get("otioClip"), "Missing `otioClip` data" @@ -159,6 +175,46 @@ class PrecollectInstances(pyblish.api.ContextPlugin): self.log.debug( "_ instance.data: {}".format(pformat(instance.data))) + def create_audio_instance(self, context, **data): + master_layer = data.get("heroTrack") + + if not master_layer: + return + + asset = data.get("asset") + item = data.get("item") + clip_name = item.name() + + asset = data["asset"] + subset = "audioMain" + + # insert family into families + family = "audio" + + # form label + label = asset + if asset != clip_name: + label += " ({}) ".format(clip_name) + label += " {}".format(subset) + label += " [{}]".format(family) + + data.update({ + "name": "{}_{}".format(asset, subset), + "label": label, + "subset": subset, + "asset": asset, + "family": family, + "families": ["clip"] + }) + # remove review track attr if any + data.pop("reviewTrack") + + # create instance + instance = context.create_instance(**data) + self.log.info("Creating instance: {}".format(instance)) + self.log.debug( + "_ instance.data: {}".format(pformat(instance.data))) + def get_otio_clip_instance_data(self, otio_timeline, track_item): """ Return otio objects for timeline, track and clip diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index cf40104645..016efa6499 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -26,10 +26,6 @@ class ExtractThumbnail(openpype.api.Extractor): def process(self, instance): self.log.info("Extracting capture..") - start = cmds.currentTime(query=True) - end = cmds.currentTime(query=True) - self.log.info("start: {}, end: {}".format(start, end)) - camera = instance.data['review_camera'] capture_preset = "" @@ -50,8 +46,8 @@ class ExtractThumbnail(openpype.api.Extractor): # preset['compression'] = "qt" preset['quality'] = 50 preset['compression'] = "jpg" - preset['start_frame'] = start - preset['end_frame'] = end + preset['start_frame'] = instance.data["frameStart"] + preset['end_frame'] = instance.data["frameStart"] preset['camera_options'] = { "displayGateMask": False, "displayResolution": False, diff --git a/openpype/lib/__init__.py b/openpype/lib/__init__.py index 457ceb1d56..838c5aa7a1 100644 --- a/openpype/lib/__init__.py +++ b/openpype/lib/__init__.py @@ -139,6 +139,7 @@ from .editorial import ( trim_media_range, range_from_frames, frames_to_secons, + frames_to_timecode, make_sequence_collection ) @@ -246,5 +247,6 @@ __all__ = [ "trim_media_range", "range_from_frames", "frames_to_secons", + "frames_to_timecode", "make_sequence_collection" ] diff --git a/openpype/lib/editorial.py b/openpype/lib/editorial.py index 1dbc4d7954..bf9a0cb506 100644 --- a/openpype/lib/editorial.py +++ b/openpype/lib/editorial.py @@ -137,6 +137,11 @@ def frames_to_secons(frames, framerate): return _ot.to_seconds(rt) +def frames_to_timecode(frames, framerate): + rt = _ot.from_frames(frames, framerate) + return _ot.to_timecode(rt) + + def make_sequence_collection(path, otio_range, metadata): """ Make collection from path otio range and otio metadata. diff --git a/openpype/plugins/publish/collect_otio_subset_resources.py b/openpype/plugins/publish/collect_otio_subset_resources.py index d687c1920a..cebfc90630 100644 --- a/openpype/plugins/publish/collect_otio_subset_resources.py +++ b/openpype/plugins/publish/collect_otio_subset_resources.py @@ -22,6 +22,10 @@ class CollectOcioSubsetResources(pyblish.api.InstancePlugin): hosts = ["resolve", "hiero"] def process(self, instance): + + if "audio" in instance.data["family"]: + return + if not instance.data.get("representations"): instance.data["representations"] = list() version_data = dict() diff --git a/openpype/plugins/publish/extract_otio_audio_tracks.py b/openpype/plugins/publish/extract_otio_audio_tracks.py new file mode 100644 index 0000000000..43e40097f7 --- /dev/null +++ b/openpype/plugins/publish/extract_otio_audio_tracks.py @@ -0,0 +1,295 @@ +import os +import pyblish +import openpype.api +from openpype.lib import ( + get_ffmpeg_tool_path +) +import tempfile +import opentimelineio as otio + + +class ExtractOtioAudioTracks(pyblish.api.ContextPlugin): + """Extract Audio tracks from OTIO timeline. + + Process will merge all found audio tracks into one long .wav file at frist + stage. Then it will trim it into individual short audio files relative to + asset length and add it to each marked instance data representation. This + is influenced by instance data audio attribute """ + + order = pyblish.api.ExtractorOrder - 0.44 + label = "Extract OTIO Audio Tracks" + hosts = ["hiero", "resolve"] + + # FFmpeg tools paths + ffmpeg_path = get_ffmpeg_tool_path("ffmpeg") + + def process(self, context): + """Convert otio audio track's content to audio representations + + Args: + context (pyblish.Context): context of publisher + """ + # split the long audio file to peces devided by isntances + audio_instances = self.get_audio_instances(context) + self.log.debug("Audio instances: {}".format(len(audio_instances))) + + if len(audio_instances) < 1: + self.log.info("No audio instances available") + return + + # get sequence + otio_timeline = context.data["otioTimeline"] + + # temp file + audio_temp_fpath = self.create_temp_file("audio") + + # get all audio inputs from otio timeline + audio_inputs = self.get_audio_track_items(otio_timeline) + + # create empty audio with longest duration + empty = self.create_empty(audio_inputs) + + # add empty to list of audio inputs + audio_inputs.insert(0, empty) + + # create cmd + cmd = self.ffmpeg_path + " " + cmd += self.create_cmd(audio_inputs) + cmd += audio_temp_fpath + + # run subprocess + self.log.debug("Executing: {}".format(cmd)) + openpype.api.run_subprocess( + cmd, shell=True, logger=self.log + ) + + # remove empty + os.remove(empty["mediaPath"]) + + # cut instance framerange and add to representations + self.add_audio_to_instances(audio_temp_fpath, audio_instances) + + # remove full mixed audio file + os.remove(audio_temp_fpath) + + def add_audio_to_instances(self, audio_file, instances): + created_files = [] + for inst in instances: + name = inst.data["asset"] + + recycling_file = [f for f in created_files if name in f] + + # frameranges + timeline_in_h = inst.data["clipInH"] + timeline_out_h = inst.data["clipOutH"] + fps = inst.data["fps"] + + # create duration + duration = (timeline_out_h - timeline_in_h) + 1 + + # ffmpeg generate new file only if doesnt exists already + if not recycling_file: + # convert to seconds + start_sec = float(timeline_in_h / fps) + duration_sec = float(duration / fps) + + # temp audio file + audio_fpath = self.create_temp_file(name) + + cmd = " ".join([ + self.ffmpeg_path, + "-ss {}".format(start_sec), + "-t {}".format(duration_sec), + "-i {}".format(audio_file), + audio_fpath + ]) + + # run subprocess + self.log.debug("Executing: {}".format(cmd)) + openpype.api.run_subprocess( + cmd, shell=True, logger=self.log + ) + else: + audio_fpath = recycling_file.pop() + + if "audio" in (inst.data["families"] + [inst.data["family"]]): + # create empty representation attr + if "representations" not in inst.data: + inst.data["representations"] = [] + # add to representations + inst.data["representations"].append({ + "files": os.path.basename(audio_fpath), + "name": "wav", + "ext": "wav", + "stagingDir": os.path.dirname(audio_fpath), + "frameStart": 0, + "frameEnd": duration + }) + + elif "reviewAudio" in inst.data.keys(): + audio_attr = inst.data.get("audio") or [] + audio_attr.append({ + "filename": audio_fpath, + "offset": 0 + }) + inst.data["audio"] = audio_attr + + # add generated audio file to created files for recycling + if audio_fpath not in created_files: + created_files.append(audio_fpath) + + def get_audio_instances(self, context): + """Return only instances which are having audio in families + + Args: + context (pyblish.context): context of publisher + + Returns: + list: list of selected instances + """ + return [ + _i for _i in context + # filter only those with audio family + # and also with reviewAudio data key + if bool("audio" in ( + _i.data.get("families", []) + [_i.data["family"]]) + ) or _i.data.get("reviewAudio") + ] + + def get_audio_track_items(self, otio_timeline): + """Get all audio clips form OTIO audio tracks + + Args: + otio_timeline (otio.schema.timeline): timeline object + + Returns: + list: list of audio clip dictionaries + """ + output = [] + # go trough all audio tracks + for otio_track in otio_timeline.tracks: + if "Audio" not in otio_track.kind: + continue + self.log.debug("_" * 50) + playhead = 0 + for otio_clip in otio_track: + self.log.debug(otio_clip) + if isinstance(otio_clip, otio.schema.Gap): + playhead += otio_clip.source_range.duration.value + elif isinstance(otio_clip, otio.schema.Clip): + start = otio_clip.source_range.start_time.value + duration = otio_clip.source_range.duration.value + fps = otio_clip.source_range.start_time.rate + media_path = otio_clip.media_reference.target_url + input = { + "mediaPath": media_path, + "delayFrame": playhead, + "startFrame": start, + "durationFrame": duration, + "delayMilSec": int(float(playhead / fps) * 1000), + "startSec": float(start / fps), + "durationSec": float(duration / fps), + "fps": fps + } + if input not in output: + output.append(input) + self.log.debug("__ input: {}".format(input)) + playhead += otio_clip.source_range.duration.value + + return output + + def create_empty(self, inputs): + """Create an empty audio file used as duration placeholder + + Args: + inputs (list): list of audio clip dictionaries + + Returns: + dict: audio clip dictionary + """ + # temp file + empty_fpath = self.create_temp_file("empty") + + # get all end frames + end_secs = [(_i["delayFrame"] + _i["durationFrame"]) / _i["fps"] + for _i in inputs] + # get the max of end frames + max_duration_sec = max(end_secs) + + # create empty cmd + cmd = " ".join([ + self.ffmpeg_path, + "-f lavfi", + "-i anullsrc=channel_layout=stereo:sample_rate=48000", + "-t {}".format(max_duration_sec), + empty_fpath + ]) + + # generate empty with ffmpeg + # run subprocess + self.log.debug("Executing: {}".format(cmd)) + + openpype.api.run_subprocess( + cmd, shell=True, logger=self.log + ) + + # return dict with output + return { + "mediaPath": empty_fpath, + "delayMilSec": 0, + "startSec": 0.00, + "durationSec": max_duration_sec + } + + def create_cmd(self, inputs): + """Creating multiple input cmd string + + Args: + inputs (list): list of input dicts. Order mater. + + Returns: + str: the command body + + """ + # create cmd segments + _inputs = "" + _filters = "-filter_complex \"" + _channels = "" + for index, input in enumerate(inputs): + input_format = input.copy() + input_format.update({"i": index}) + _inputs += ( + "-ss {startSec} " + "-t {durationSec} " + "-i \"{mediaPath}\" " + ).format(**input_format) + + _filters += "[{i}]adelay={delayMilSec}:all=1[r{i}]; ".format( + **input_format) + _channels += "[r{}]".format(index) + + # merge all cmd segments together + cmd = _inputs + _filters + _channels + cmd += str( + "amix=inputs={inputs}:duration=first:" + "dropout_transition=1000,volume={inputs}[a]\" " + ).format(inputs=len(inputs)) + cmd += "-map \"[a]\" " + + return cmd + + def create_temp_file(self, name): + """Create temp wav file + + Args: + name (str): name to be used in file name + + Returns: + str: temp fpath + """ + return os.path.normpath( + tempfile.mktemp( + prefix="pyblish_tmp_{}_".format(name), + suffix=".wav" + ) + ) diff --git a/openpype/settings/defaults/project_settings/aftereffects.json b/openpype/settings/defaults/project_settings/aftereffects.json new file mode 100644 index 0000000000..f54dbb9612 --- /dev/null +++ b/openpype/settings/defaults/project_settings/aftereffects.json @@ -0,0 +1,18 @@ +{ + "publish": { + "ValidateSceneSettings": { + "enabled": true, + "optional": true, + "active": true, + "skip_resolution_check": [".*"], + "skip_timelines_check": [".*"] + }, + "AfterEffectsSubmitDeadline": { + "use_published": true, + "priority": 50, + "primary_pool": "", + "secondary_pool": "", + "chunk_size": 1000000 + } + } +} \ No newline at end of file diff --git a/openpype/settings/entities/dict_mutable_keys_entity.py b/openpype/settings/entities/dict_mutable_keys_entity.py index ef0124c0f0..4839dbcdc2 100644 --- a/openpype/settings/entities/dict_mutable_keys_entity.py +++ b/openpype/settings/entities/dict_mutable_keys_entity.py @@ -1,6 +1,5 @@ import re import copy - from .lib import ( NOT_SET, OverrideState @@ -94,11 +93,18 @@ class DictMutableKeysEntity(EndpointEntity): for key in prev_keys: self.pop(key) + def _convert_to_valid_type(self, value): + try: + return dict(value) + except Exception: + pass + return super(DictMutableKeysEntity, self)._convert_to_valid_type(value) + def set_key_value(self, key, value): # TODO Check for value type if is Settings entity? child_obj = self.children_by_key.get(key) if not child_obj: - if not KEY_REGEX.match(key): + if not self.store_as_list and not KEY_REGEX.match(key): raise InvalidKeySymbols(self.path, key) child_obj = self.add_key(key) @@ -112,7 +118,7 @@ class DictMutableKeysEntity(EndpointEntity): if new_key == old_key: return - if not KEY_REGEX.match(new_key): + if not self.store_as_list and not KEY_REGEX.match(new_key): raise InvalidKeySymbols(self.path, new_key) self.children_by_key[new_key] = self.children_by_key.pop(old_key) @@ -125,11 +131,15 @@ class DictMutableKeysEntity(EndpointEntity): self._has_project_override = True self.on_change() - def _add_key(self, key): + def _add_key(self, key, _ingore_key_validation=False): if key in self.children_by_key: self.pop(key) - if not KEY_REGEX.match(key): + if ( + not _ingore_key_validation + and not self.store_as_list + and not KEY_REGEX.match(key) + ): raise InvalidKeySymbols(self.path, key) if self.value_is_env_group: @@ -194,6 +204,7 @@ class DictMutableKeysEntity(EndpointEntity): self.children_by_key = {} self.children_label_by_id = {} + self.store_as_list = self.schema_data.get("store_as_list") or False self.value_is_env_group = ( self.schema_data.get("value_is_env_group") or False ) @@ -237,6 +248,10 @@ class DictMutableKeysEntity(EndpointEntity): if used_temp_label: self.label = None + if self.value_is_env_group and self.store_as_list: + reason = "Item can't store environments metadata to list output." + raise EntitySchemaError(self, reason) + if not self.schema_data.get("object_type"): reason = ( "Modifiable dictionary must have specified `object_type`." @@ -332,6 +347,7 @@ class DictMutableKeysEntity(EndpointEntity): using_project_overrides = False using_studio_overrides = False + using_default_values = False if ( state is OverrideState.PROJECT and self.had_project_override @@ -349,14 +365,28 @@ class DictMutableKeysEntity(EndpointEntity): metadata = self._studio_override_metadata else: + using_default_values = True value = self._default_value metadata = self._default_metadata if value is NOT_SET: + using_default_values = False value = self.value_on_not_set + using_values_from_state = False + if state is OverrideState.PROJECT: + using_values_from_state = using_project_overrides + elif state is OverrideState.STUDIO: + using_values_from_state = using_studio_overrides + elif state is OverrideState.DEFAULTS: + using_values_from_state = using_default_values + new_value = copy.deepcopy(value) + if using_values_from_state: + initial_value = copy.deepcopy(value) + initial_value.update(metadata) + # Simulate `clear` method without triggering value change for key in tuple(self.children_by_key.keys()): self.children_by_key.pop(key) @@ -369,30 +399,51 @@ class DictMutableKeysEntity(EndpointEntity): children_label_by_id = {} metadata_labels = metadata.get(M_DYNAMIC_KEY_LABEL) or {} for _key, _value in new_value.items(): - if not KEY_REGEX.match(_key): + label = metadata_labels.get(_key) + if self.store_as_list or KEY_REGEX.match(_key): + child_entity = self._add_key(_key) + else: # Replace invalid characters with underscore # - this is safety to not break already existing settings - _key = re.sub( - r"[^{}]+".format(KEY_ALLOWED_SYMBOLS), - "_", - _key - ) + new_key = self._convert_to_regex_valid_key(_key) + if not using_values_from_state: + child_entity = self._add_key(new_key) + else: + child_entity = self._add_key( + _key, _ingore_key_validation=True + ) + self.change_key(_key, new_key) + _key = new_key + + if not label: + label = metadata_labels.get(new_key) - child_entity = self._add_key(_key) child_entity.update_default_value(_value) if using_project_overrides: child_entity.update_project_value(_value) elif using_studio_overrides: child_entity.update_studio_value(_value) - label = metadata_labels.get(_key) if label: children_label_by_id[child_entity.id] = label child_entity.set_override_state(state) self.children_label_by_id = children_label_by_id - self.initial_value = self.settings_value() + _settings_value = self.settings_value() + if using_values_from_state: + if _settings_value is NOT_SET: + initial_value = NOT_SET + else: + initial_value = _settings_value + self.initial_value = initial_value + + def _convert_to_regex_valid_key(self, key): + return re.sub( + r"[^{}]+".format(KEY_ALLOWED_SYMBOLS), + "_", + key + ) def children_key_by_id(self): return { @@ -402,6 +453,12 @@ class DictMutableKeysEntity(EndpointEntity): @property def value(self): + if self.store_as_list: + output = [] + for key, child_entity in self.children_by_key.items(): + output.append(key, child_entity.value) + return output + output = {} for key, child_entity in self.children_by_key.items(): output[key] = child_entity.value @@ -481,6 +538,13 @@ class DictMutableKeysEntity(EndpointEntity): return False def _settings_value(self): + if self.store_as_list: + output = [] + for key, child_entity in self.children_by_key.items(): + child_value = child_entity.settings_value() + output.append([key, child_value]) + return output + output = {} for key, child_entity in self.children_by_key.items(): child_value = child_entity.settings_value() @@ -563,7 +627,8 @@ class DictMutableKeysEntity(EndpointEntity): # Create new children for _key, _value in new_value.items(): - child_entity = self._add_key(_key) + new_key = self._convert_to_regex_valid_key(_key) + child_entity = self._add_key(new_key) child_entity.update_default_value(_value) label = metadata_labels.get(_key) if label: @@ -608,7 +673,8 @@ class DictMutableKeysEntity(EndpointEntity): # Create new children for _key, _value in new_value.items(): - child_entity = self._add_key(_key) + new_key = self._convert_to_regex_valid_key(_key) + child_entity = self._add_key(new_key) child_entity.update_default_value(_value) if self._has_studio_override: child_entity.update_studio_value(_value) diff --git a/openpype/settings/entities/schemas/projects_schema/schema_main.json b/openpype/settings/entities/schemas/projects_schema/schema_main.json index 6bc158aa60..b4666b302a 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_main.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_main.json @@ -78,6 +78,10 @@ "type": "schema", "name": "schema_project_hiero" }, + { + "type": "schema", + "name": "schema_project_aftereffects" + }, { "type": "schema", "name": "schema_project_harmony" diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_aftereffects.json b/openpype/settings/entities/schemas/projects_schema/schema_project_aftereffects.json new file mode 100644 index 0000000000..63bf9274a3 --- /dev/null +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_aftereffects.json @@ -0,0 +1,90 @@ +{ + "type": "dict", + "collapsible": true, + "key": "aftereffects", + "label": "AfterEffects", + "is_file": true, + "children": [ + { + "type": "dict", + "collapsible": true, + "key": "publish", + "label": "Publish plugins", + "children": [ + { + "type": "dict", + "collapsible": true, + "key": "ValidateSceneSettings", + "label": "Validate Scene Settings", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "active", + "label": "Active" + }, + { + "type": "label", + "label": "Validate if FPS and Resolution match shot data" + }, + { + "type": "list", + "key": "skip_resolution_check", + "object_type": "text", + "label": "Skip Resolution Check for Tasks" + }, + { + "type": "list", + "key": "skip_timelines_check", + "object_type": "text", + "label": "Skip Timeline Check for Tasks" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "key": "AfterEffectsSubmitDeadline", + "label": "AfterEffects Submit to Deadline", + "children": [ + { + "type": "boolean", + "key": "use_published", + "label": "Use Published scene" + }, + { + "type": "number", + "key": "priority", + "label": "Priority" + }, + { + "type": "text", + "key": "primary_pool", + "label": "Primary Pool" + }, + { + "type": "text", + "key": "secondary_pool", + "label": "Secondary Pool" + }, + { + "type": "number", + "key": "chunk_size", + "label": "Frames Per Task" + } + ] + } + ] + } + ] +} diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/schema_blender.json b/openpype/settings/entities/schemas/system_schema/host_settings/schema_blender.json index e72b1fac5b..0a6c8ca035 100644 --- a/openpype/settings/entities/schemas/system_schema/host_settings/schema_blender.json +++ b/openpype/settings/entities/schemas/system_schema/host_settings/schema_blender.json @@ -23,7 +23,6 @@ "type": "dict-modifiable", "key": "variants", "collapsible_key": true, - "dynamic_label": false, "use_label_wrap": false, "object_type": { "type": "dict", diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/schema_djv.json b/openpype/settings/entities/schemas/system_schema/host_settings/schema_djv.json index 229ca42b04..d09f038892 100644 --- a/openpype/settings/entities/schemas/system_schema/host_settings/schema_djv.json +++ b/openpype/settings/entities/schemas/system_schema/host_settings/schema_djv.json @@ -23,7 +23,6 @@ "type": "dict-modifiable", "key": "variants", "collapsible_key": true, - "dynamic_label": false, "use_label_wrap": false, "object_type": { "type": "dict", diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/schema_houdini.json b/openpype/settings/entities/schemas/system_schema/host_settings/schema_houdini.json index ee88d90e8e..5390b9b78f 100644 --- a/openpype/settings/entities/schemas/system_schema/host_settings/schema_houdini.json +++ b/openpype/settings/entities/schemas/system_schema/host_settings/schema_houdini.json @@ -23,7 +23,6 @@ "type": "dict-modifiable", "key": "variants", "collapsible_key": true, - "dynamic_label": false, "use_label_wrap": false, "object_type": { "type": "dict", diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/schema_maya.json b/openpype/settings/entities/schemas/system_schema/host_settings/schema_maya.json index 9a81eda88d..97854a3945 100644 --- a/openpype/settings/entities/schemas/system_schema/host_settings/schema_maya.json +++ b/openpype/settings/entities/schemas/system_schema/host_settings/schema_maya.json @@ -23,7 +23,6 @@ "type": "dict-modifiable", "key": "variants", "collapsible_key": true, - "dynamic_label": false, "use_label_wrap": false, "object_type": { "type": "dict", diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/schema_shell.json b/openpype/settings/entities/schemas/system_schema/host_settings/schema_shell.json index fcbb415b12..986f83a9fc 100644 --- a/openpype/settings/entities/schemas/system_schema/host_settings/schema_shell.json +++ b/openpype/settings/entities/schemas/system_schema/host_settings/schema_shell.json @@ -19,7 +19,6 @@ "type": "dict-modifiable", "key": "variants", "collapsible_key": true, - "dynamic_label": false, "use_label_wrap": false, "object_type": { "type": "dict", diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/schema_tvpaint.json b/openpype/settings/entities/schemas/system_schema/host_settings/schema_tvpaint.json index 3c13336eb1..c39e6f7a30 100644 --- a/openpype/settings/entities/schemas/system_schema/host_settings/schema_tvpaint.json +++ b/openpype/settings/entities/schemas/system_schema/host_settings/schema_tvpaint.json @@ -23,7 +23,6 @@ "type": "dict-modifiable", "key": "variants", "collapsible_key": true, - "dynamic_label": false, "use_label_wrap": false, "object_type": { "type": "dict", diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/schema_unreal.json b/openpype/settings/entities/schemas/system_schema/host_settings/schema_unreal.json index 1752899533..df5ec0e6fa 100644 --- a/openpype/settings/entities/schemas/system_schema/host_settings/schema_unreal.json +++ b/openpype/settings/entities/schemas/system_schema/host_settings/schema_unreal.json @@ -23,7 +23,6 @@ "type": "dict-modifiable", "key": "variants", "collapsible_key": true, - "dynamic_label": false, "use_label_wrap": false, "object_type": { "type": "dict", diff --git a/openpype/settings/entities/schemas/system_schema/host_settings/template_nuke.json b/openpype/settings/entities/schemas/system_schema/host_settings/template_nuke.json index 0055d0b191..22398ba227 100644 --- a/openpype/settings/entities/schemas/system_schema/host_settings/template_nuke.json +++ b/openpype/settings/entities/schemas/system_schema/host_settings/template_nuke.json @@ -24,7 +24,6 @@ "type": "dict-modifiable", "key": "variants", "collapsible_key": true, - "dynamic_label": false, "use_label_wrap": false, "object_type": { "type": "dict", diff --git a/openpype/tools/settings/settings/dict_mutable_widget.py b/openpype/tools/settings/settings/dict_mutable_widget.py index d29b72f2fc..df6525e86a 100644 --- a/openpype/tools/settings/settings/dict_mutable_widget.py +++ b/openpype/tools/settings/settings/dict_mutable_widget.py @@ -32,14 +32,15 @@ def create_remove_btn(parent): class ModifiableDictEmptyItem(QtWidgets.QWidget): - def __init__(self, entity_widget, parent): + def __init__(self, entity_widget, store_as_list, parent): super(ModifiableDictEmptyItem, self).__init__(parent) self.entity_widget = entity_widget self.collapsible_key = entity_widget.entity.collapsible_key self.ignore_input_changes = entity_widget.ignore_input_changes + self.store_as_list = store_as_list self.is_duplicated = False - self.key_is_valid = False + self.key_is_valid = store_as_list if self.collapsible_key: self.create_collapsible_ui() @@ -101,7 +102,8 @@ class ModifiableDictEmptyItem(QtWidgets.QWidget): def _on_key_change(self): key = self.key_input.text() - self.key_is_valid = KEY_REGEX.match(key) + if not self.store_as_list: + self.key_is_valid = KEY_REGEX.match(key) if self.ignore_input_changes: return @@ -161,9 +163,11 @@ class ModifiableDictEmptyItem(QtWidgets.QWidget): class ModifiableDictItem(QtWidgets.QWidget): - def __init__(self, collapsible_key, entity, entity_widget): + def __init__(self, collapsible_key, store_as_list, entity, entity_widget): super(ModifiableDictItem, self).__init__(entity_widget.content_widget) + self.store_as_list = store_as_list + self.collapsible_key = collapsible_key self.entity = entity self.entity_widget = entity_widget @@ -171,7 +175,7 @@ class ModifiableDictItem(QtWidgets.QWidget): self.ignore_input_changes = entity_widget.ignore_input_changes self.is_key_duplicated = False - self.key_is_valid = False + self.key_is_valid = store_as_list self.is_required = False self.origin_key = None @@ -401,7 +405,8 @@ class ModifiableDictItem(QtWidgets.QWidget): def _on_key_change(self): key = self.key_value() - self.key_is_valid = KEY_REGEX.match(key) + if not self.store_as_list: + self.key_is_valid = KEY_REGEX.match(key) if self.ignore_input_changes: return @@ -607,7 +612,7 @@ class DictMutableKeysWidget(BaseWidget): self.add_required_keys() self.empty_row = ModifiableDictEmptyItem( - self, self.content_widget + self, self.entity.store_as_list, self.content_widget ) self.content_layout.addWidget(self.empty_row) @@ -734,7 +739,8 @@ class DictMutableKeysWidget(BaseWidget): def add_widget_for_child(self, child_entity): input_field = ModifiableDictItem( - self.entity.collapsible_key, child_entity, self + self.entity.collapsible_key, self.entity.store_as_list, + child_entity, self ) self.input_fields.append(input_field) diff --git a/openpype/tools/standalonepublish/widgets/widget_family.py b/openpype/tools/standalonepublish/widgets/widget_family.py index 50335e3109..86663c8ee0 100644 --- a/openpype/tools/standalonepublish/widgets/widget_family.py +++ b/openpype/tools/standalonepublish/widgets/widget_family.py @@ -255,9 +255,9 @@ class FamilyWidget(QtWidgets.QWidget): defaults = list(plugin.defaults) # Replace - compare_regex = re.compile( - subset_name.replace(user_input_text, "(.+)") - ) + compare_regex = re.compile(re.sub( + user_input_text, "(.+)", subset_name, flags=re.IGNORECASE + )) subset_hints = set() if user_input_text: for _name in existing_subset_names: diff --git a/openpype/version.py b/openpype/version.py index 68f154f5eb..27186ad2bb 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.0.0-rc3" +__version__ = "3.0.0-rc4" diff --git a/pyproject.toml b/pyproject.toml index 42ace686cc..1c3c5ad44e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "OpenPype" -version = "3.0.0-rc3" +version = "3.0.0-rc4" description = "Open VFX and Animation pipeline with support." authors = ["OpenPype Team "] license = "MIT License" @@ -97,9 +97,9 @@ url = "https://distribute.openpype.io/thirdparty/oiio_tools-2.2.0-windows.zip" hash = "fd2e00278e01e85dcee7b4a6969d1a16f13016ec16700fb0366dbb1b1f3c37ad" [openpype.thirdparty.oiio.linux] -url = "https://distribute.openpype.io/thirdparty/oiio-2.2.0-linux.tgz" -hash = "sha256:..." +url = "https://distribute.openpype.io/thirdparty/oiio_tools-2.2.12-linux.tgz" +hash = "de63a8bf7f6c45ff59ecafeba13123f710c2cbc1783ec9e0b938e980d4f5c37f" [openpype.thirdparty.oiio.darwin] url = "https://distribute.openpype.io/thirdparty/oiio-2.2.0-darwin.tgz" -hash = "sha256:..." \ No newline at end of file +hash = "sha256:..." diff --git a/tests/igniter/test_bootstrap_repos.py b/tests/igniter/test_bootstrap_repos.py index 6c70380ab6..54950c546e 100644 --- a/tests/igniter/test_bootstrap_repos.py +++ b/tests/igniter/test_bootstrap_repos.py @@ -5,72 +5,75 @@ import sys from collections import namedtuple from pathlib import Path from zipfile import ZipFile +from uuid import uuid4 import appdirs import pytest from igniter.bootstrap_repos import BootstrapRepos -from igniter.bootstrap_repos import PypeVersion -from pype.lib import OpenPypeSettingsRegistry +from igniter.bootstrap_repos import OpenPypeVersion +from igniter.user_settings import OpenPypeSettingsRegistry @pytest.fixture def fix_bootstrap(tmp_path, pytestconfig): + """This will fix BoostrapRepos with temp paths.""" bs = BootstrapRepos() bs.live_repo_dir = pytestconfig.rootpath / 'repos' bs.data_dir = tmp_path return bs -def test_pype_version(): - v1 = PypeVersion(1, 2, 3) +def test_openpype_version(): + """Test determination of OpenPype versions.""" + v1 = OpenPypeVersion(1, 2, 3) assert str(v1) == "1.2.3" - v2 = PypeVersion(1, 2, 3, client="x") + v2 = OpenPypeVersion(1, 2, 3, client="x") assert str(v2) == "1.2.3-x" assert v1 < v2 - v3 = PypeVersion(1, 2, 3, variant="staging") + v3 = OpenPypeVersion(1, 2, 3, variant="staging") assert str(v3) == "1.2.3-staging" - v4 = PypeVersion(1, 2, 3, variant="staging", client="client") + v4 = OpenPypeVersion(1, 2, 3, variant="staging", client="client") assert str(v4) == "1.2.3-client-staging" assert v3 < v4 assert v1 < v4 - v5 = PypeVersion(1, 2, 3, variant="foo", client="x") + v5 = OpenPypeVersion(1, 2, 3, variant="foo", client="x") assert str(v5) == "1.2.3-x" assert v4 < v5 - v6 = PypeVersion(1, 2, 3, variant="foo") + v6 = OpenPypeVersion(1, 2, 3, variant="foo") assert str(v6) == "1.2.3" - v7 = PypeVersion(2, 0, 0) + v7 = OpenPypeVersion(2, 0, 0) assert v1 < v7 - v8 = PypeVersion(0, 1, 5) + v8 = OpenPypeVersion(0, 1, 5) assert v8 < v7 - v9 = PypeVersion(1, 2, 4) + v9 = OpenPypeVersion(1, 2, 4) assert v9 > v1 - v10 = PypeVersion(1, 2, 2) + v10 = OpenPypeVersion(1, 2, 2) assert v10 < v1 - v11 = PypeVersion(1, 2, 3, path=Path("/foo/bar")) + v11 = OpenPypeVersion(1, 2, 3, path=Path("/foo/bar")) assert v10 < v11 assert v5 == v2 sort_versions = [ - PypeVersion(3, 2, 1), - PypeVersion(1, 2, 3), - PypeVersion(0, 0, 1), - PypeVersion(4, 8, 10), - PypeVersion(4, 8, 20), - PypeVersion(4, 8, 9), - PypeVersion(1, 2, 3, variant="staging"), - PypeVersion(1, 2, 3, client="client") + OpenPypeVersion(3, 2, 1), + OpenPypeVersion(1, 2, 3), + OpenPypeVersion(0, 0, 1), + OpenPypeVersion(4, 8, 10), + OpenPypeVersion(4, 8, 20), + OpenPypeVersion(4, 8, 9), + OpenPypeVersion(1, 2, 3, variant="staging"), + OpenPypeVersion(1, 2, 3, client="client") ] res = sorted(sort_versions) @@ -88,25 +91,22 @@ def test_pype_version(): "5.6.3", "5.6.3-staging" ] - res_versions = [] - for v in str_versions: - res_versions.append(PypeVersion(version=v)) - + res_versions = [OpenPypeVersion(version=v) for v in str_versions] sorted_res_versions = sorted(res_versions) assert str(sorted_res_versions[0]) == str_versions[0] assert str(sorted_res_versions[-1]) == str_versions[5] with pytest.raises(ValueError): - _ = PypeVersion() + _ = OpenPypeVersion() with pytest.raises(ValueError): - _ = PypeVersion(major=1) + _ = OpenPypeVersion(major=1) with pytest.raises(ValueError): - _ = PypeVersion(version="booobaa") + _ = OpenPypeVersion(version="booobaa") - v11 = PypeVersion(version="4.6.7-client-staging") + v11 = OpenPypeVersion(version="4.6.7-client-staging") assert v11.major == 4 assert v11.minor == 6 assert v11.subversion == 7 @@ -115,15 +115,15 @@ def test_pype_version(): def test_get_main_version(): - ver = PypeVersion(1, 2, 3, variant="staging", client="foo") + ver = OpenPypeVersion(1, 2, 3, variant="staging", client="foo") assert ver.get_main_version() == "1.2.3" def test_get_version_path_from_list(): versions = [ - PypeVersion(1, 2, 3, path=Path('/foo/bar')), - PypeVersion(3, 4, 5, variant="staging", path=Path("/bar/baz")), - PypeVersion(6, 7, 8, client="x", path=Path("boo/goo")) + OpenPypeVersion(1, 2, 3, path=Path('/foo/bar')), + OpenPypeVersion(3, 4, 5, variant="staging", path=Path("/bar/baz")), + OpenPypeVersion(6, 7, 8, client="x", path=Path("boo/goo")) ] path = BootstrapRepos.get_version_path_from_list( "3.4.5-staging", versions) @@ -131,7 +131,7 @@ def test_get_version_path_from_list(): assert path == Path("/bar/baz") -def test_search_string_for_pype_version(printer): +def test_search_string_for_openpype_version(printer): strings = [ ("3.0.1", True), ("foo-3.0", False), @@ -142,106 +142,112 @@ def test_search_string_for_pype_version(printer): ] for ver_string in strings: printer(f"testing {ver_string[0]} should be {ver_string[1]}") - assert PypeVersion.version_in_str(ver_string[0])[0] == ver_string[1] + assert OpenPypeVersion.version_in_str(ver_string[0])[0] == \ + ver_string[1] @pytest.mark.slow -def test_install_live_repos(fix_bootstrap, printer): - pype_version = fix_bootstrap.create_version_from_live_code() +def test_install_live_repos(fix_bootstrap, printer, monkeypatch, pytestconfig): + monkeypatch.setenv("OPENPYPE_ROOT", pytestconfig.rootpath.as_posix()) + monkeypatch.setenv("OPENPYPE_DATABASE_NAME", str(uuid4())) + openpype_version = fix_bootstrap.create_version_from_live_code() sep = os.path.sep expected_paths = [ - f"{pype_version.path}{sep}repos{sep}avalon-core", - f"{pype_version.path}{sep}repos{sep}avalon-unreal-integration", - f"{pype_version.path}" + f"{openpype_version.path}{sep}repos{sep}avalon-core", + f"{openpype_version.path}{sep}repos{sep}avalon-unreal-integration", + f"{openpype_version.path}" ] printer("testing zip creation") - assert os.path.exists(pype_version.path), "zip archive was not created" - fix_bootstrap.add_paths_from_archive(pype_version.path) + assert os.path.exists(openpype_version.path), "zip archive was not created" + fix_bootstrap.add_paths_from_archive(openpype_version.path) for ep in expected_paths: assert ep in sys.path, f"{ep} not set correctly" - printer("testing pype imported") - del sys.modules["pype"] - import pype # noqa: F401 + printer("testing openpype imported") + try: + del sys.modules["openpype"] + except KeyError: + # wasn't imported before + pass + import openpype # noqa: F401 - # test if pype is imported from specific location in zip - assert "pype" in sys.modules.keys(), "Pype not imported" - assert sys.modules["pype"].__file__ == \ - f"{pype_version.path}{sep}pype{sep}__init__.py" + # test if openpype is imported from specific location in zip + assert "openpype" in sys.modules.keys(), "OpenPype not imported" + assert sys.modules["openpype"].__file__ == \ + f"{openpype_version.path}{sep}openpype{sep}__init__.py" -def test_find_pype(fix_bootstrap, tmp_path_factory, monkeypatch, printer): - - test_pype = namedtuple("Pype", "prefix version suffix type valid") +def test_find_openpype(fix_bootstrap, tmp_path_factory, monkeypatch, printer): + test_openpype = namedtuple("OpenPype", "prefix version suffix type valid") test_versions_1 = [ - test_pype(prefix="foo-v", version="5.5.1", - suffix=".zip", type="zip", valid=False), - test_pype(prefix="bar-v", version="5.5.2-client", - suffix=".zip", type="zip", valid=True), - test_pype(prefix="baz-v", version="5.5.3-client-strange", - suffix=".zip", type="zip", valid=True), - test_pype(prefix="bum-v", version="5.5.4-staging", - suffix=".zip", type="zip", valid=True), - test_pype(prefix="zum-v", version="5.5.5-client-staging", - suffix=".zip", type="zip", valid=True), - test_pype(prefix="fam-v", version="5.6.3", - suffix=".zip", type="zip", valid=True), - test_pype(prefix="foo-v", version="5.6.3-staging", - suffix=".zip", type="zip", valid=True), - test_pype(prefix="fim-v", version="5.6.3", - suffix=".zip", type="zip", valid=False), - test_pype(prefix="foo-v", version="5.6.4", - suffix=".txt", type="txt", valid=False), - test_pype(prefix="foo-v", version="5.7.1", - suffix="", type="dir", valid=False), + test_openpype(prefix="foo-v", version="5.5.1", + suffix=".zip", type="zip", valid=False), + test_openpype(prefix="bar-v", version="5.5.2-client", + suffix=".zip", type="zip", valid=True), + test_openpype(prefix="baz-v", version="5.5.3-client-strange", + suffix=".zip", type="zip", valid=True), + test_openpype(prefix="bum-v", version="5.5.4-staging", + suffix=".zip", type="zip", valid=True), + test_openpype(prefix="zum-v", version="5.5.5-client-staging", + suffix=".zip", type="zip", valid=True), + test_openpype(prefix="fam-v", version="5.6.3", + suffix=".zip", type="zip", valid=True), + test_openpype(prefix="foo-v", version="5.6.3-staging", + suffix=".zip", type="zip", valid=True), + test_openpype(prefix="fim-v", version="5.6.3", + suffix=".zip", type="zip", valid=False), + test_openpype(prefix="foo-v", version="5.6.4", + suffix=".txt", type="txt", valid=False), + test_openpype(prefix="foo-v", version="5.7.1", + suffix="", type="dir", valid=False), ] test_versions_2 = [ - test_pype(prefix="foo-v", version="10.0.0", - suffix=".txt", type="txt", valid=False), - test_pype(prefix="lom-v", version="7.2.6", - suffix=".zip", type="zip", valid=True), - test_pype(prefix="bom-v", version="7.2.7-client", - suffix=".zip", type="zip", valid=True), - test_pype(prefix="woo-v", version="7.2.8-client-strange", - suffix=".zip", type="zip", valid=True), - test_pype(prefix="loo-v", version="7.2.10-client-staging", - suffix=".zip", type="zip", valid=True), - test_pype(prefix="kok-v", version="7.0.1", - suffix=".zip", type="zip", valid=True) + test_openpype(prefix="foo-v", version="10.0.0", + suffix=".txt", type="txt", valid=False), + test_openpype(prefix="lom-v", version="7.2.6", + suffix=".zip", type="zip", valid=True), + test_openpype(prefix="bom-v", version="7.2.7-client", + suffix=".zip", type="zip", valid=True), + test_openpype(prefix="woo-v", version="7.2.8-client-strange", + suffix=".zip", type="zip", valid=True), + test_openpype(prefix="loo-v", version="7.2.10-client-staging", + suffix=".zip", type="zip", valid=True), + test_openpype(prefix="kok-v", version="7.0.1", + suffix=".zip", type="zip", valid=True) ] test_versions_3 = [ - test_pype(prefix="foo-v", version="3.0.0", - suffix=".zip", type="zip", valid=True), - test_pype(prefix="goo-v", version="3.0.1", - suffix=".zip", type="zip", valid=True), - test_pype(prefix="hoo-v", version="4.1.0", - suffix=".zip", type="zip", valid=True), - test_pype(prefix="foo-v", version="4.1.2", - suffix=".zip", type="zip", valid=True), - test_pype(prefix="foo-v", version="3.0.1-client", - suffix=".zip", type="zip", valid=True), - test_pype(prefix="foo-v", version="3.0.1-client-strange", - suffix=".zip", type="zip", valid=True), - test_pype(prefix="foo-v", version="3.0.1-staging", - suffix=".zip", type="zip", valid=True), - test_pype(prefix="foo-v", version="3.0.1-client-staging", - suffix=".zip", type="zip", valid=True), - test_pype(prefix="foo-v", version="3.2.0", - suffix=".zip", type="zip", valid=True) + test_openpype(prefix="foo-v", version="3.0.0", + suffix=".zip", type="zip", valid=True), + test_openpype(prefix="goo-v", version="3.0.1", + suffix=".zip", type="zip", valid=True), + test_openpype(prefix="hoo-v", version="4.1.0", + suffix=".zip", type="zip", valid=True), + test_openpype(prefix="foo-v", version="4.1.2", + suffix=".zip", type="zip", valid=True), + test_openpype(prefix="foo-v", version="3.0.1-client", + suffix=".zip", type="zip", valid=True), + test_openpype(prefix="foo-v", version="3.0.1-client-strange", + suffix=".zip", type="zip", valid=True), + test_openpype(prefix="foo-v", version="3.0.1-staging", + suffix=".zip", type="zip", valid=True), + test_openpype(prefix="foo-v", version="3.0.1-client-staging", + suffix=".zip", type="zip", valid=True), + test_openpype(prefix="foo-v", version="3.2.0", + suffix=".zip", type="zip", valid=True) ] test_versions_4 = [ - test_pype(prefix="foo-v", version="10.0.0", - suffix="", type="dir", valid=True), - test_pype(prefix="lom-v", version="11.2.6", - suffix=".zip", type="dir", valid=False), - test_pype(prefix="bom-v", version="7.2.7-client", - suffix=".zip", type="zip", valid=True), - test_pype(prefix="woo-v", version="7.2.8-client-strange", - suffix=".zip", type="txt", valid=False) + test_openpype(prefix="foo-v", version="10.0.0", + suffix="", type="dir", valid=True), + test_openpype(prefix="lom-v", version="11.2.6", + suffix=".zip", type="dir", valid=False), + test_openpype(prefix="bom-v", version="7.2.7-client", + suffix=".zip", type="zip", valid=True), + test_openpype(prefix="woo-v", version="7.2.8-client-strange", + suffix=".zip", type="txt", valid=False) ] def _create_invalid_zip(path: Path): @@ -251,7 +257,7 @@ def test_find_pype(fix_bootstrap, tmp_path_factory, monkeypatch, printer): def _create_valid_zip(path: Path, version: str): with ZipFile(path, "w") as zf: zf.writestr( - "pype/version.py", f"__version__ = '{version}'\n\n") + "openpype/version.py", f"__version__ = '{version}'\n\n") def _create_invalid_dir(path: Path): path.mkdir(parents=True, exist_ok=True) @@ -259,9 +265,9 @@ def test_find_pype(fix_bootstrap, tmp_path_factory, monkeypatch, printer): fp.write("invalid") def _create_valid_dir(path: Path, version: str): - pype_path = path / "pype" - version_path = pype_path / "version.py" - pype_path.mkdir(parents=True, exist_ok=True) + openpype_path = path / "openpype" + version_path = openpype_path / "version.py" + openpype_path.mkdir(parents=True, exist_ok=True) with open(version_path, "w") as fp: fp.write(f"__version__ = '{version}'\n\n") @@ -283,15 +289,15 @@ def test_find_pype(fix_bootstrap, tmp_path_factory, monkeypatch, printer): with open(test_path, "w") as fp: fp.write("foo") - # in PYPE_PATH + # in OPENPYPE_PATH e_path = tmp_path_factory.mktemp("environ") # create files and directories for test for test_file in test_versions_1: _build_test_item(e_path, test_file) - # in pypePath registry - p_path = tmp_path_factory.mktemp("pypePath") + # in openPypePath registry + p_path = tmp_path_factory.mktemp("openPypePath") for test_file in test_versions_2: _build_test_item(p_path, test_file) @@ -310,10 +316,10 @@ def test_find_pype(fix_bootstrap, tmp_path_factory, monkeypatch, printer): for test_file in test_versions_4: _build_test_item(dir_path, test_file) - printer("testing finding Pype in given path ...") - result = fix_bootstrap.find_pype(g_path, include_zips=True) + printer("testing finding OpenPype in given path ...") + result = fix_bootstrap.find_openpype(g_path, include_zips=True) # we should have results as file were created - assert result is not None, "no Pype version found" + assert result is not None, "no OpenPype version found" # latest item in `result` should be latest version found. expected_path = Path( g_path / "{}{}{}".format( @@ -323,13 +329,14 @@ def test_find_pype(fix_bootstrap, tmp_path_factory, monkeypatch, printer): ) ) assert result, "nothing found" - assert result[-1].path == expected_path, "not a latest version of Pype 3" + assert result[-1].path == expected_path, ("not a latest version of " + "OpenPype 3") - monkeypatch.setenv("PYPE_PATH", e_path.as_posix()) + monkeypatch.setenv("OPENPYPE_PATH", e_path.as_posix()) - result = fix_bootstrap.find_pype(include_zips=True) + result = fix_bootstrap.find_openpype(include_zips=True) # we should have results as file were created - assert result is not None, "no Pype version found" + assert result is not None, "no OpenPype version found" # latest item in `result` should be latest version found. expected_path = Path( e_path / "{}{}{}".format( @@ -339,21 +346,23 @@ def test_find_pype(fix_bootstrap, tmp_path_factory, monkeypatch, printer): ) ) assert result, "nothing found" - assert result[-1].path == expected_path, "not a latest version of Pype 1" + assert result[-1].path == expected_path, ("not a latest version of " + "OpenPype 1") - monkeypatch.delenv("PYPE_PATH", raising=False) + monkeypatch.delenv("OPENPYPE_PATH", raising=False) # mock appdirs user_data_dir def mock_user_data_dir(*args, **kwargs): + """Mock local app data dir.""" return d_path.as_posix() monkeypatch.setattr(appdirs, "user_data_dir", mock_user_data_dir) fix_bootstrap.registry = OpenPypeSettingsRegistry() - fix_bootstrap.registry.set_item("pypePath", d_path.as_posix()) + fix_bootstrap.registry.set_item("openPypePath", d_path.as_posix()) - result = fix_bootstrap.find_pype(include_zips=True) + result = fix_bootstrap.find_openpype(include_zips=True) # we should have results as file were created - assert result is not None, "no Pype version found" + assert result is not None, "no OpenPype version found" # latest item in `result` should be latest version found. expected_path = Path( d_path / "{}{}{}".format( @@ -363,10 +372,11 @@ def test_find_pype(fix_bootstrap, tmp_path_factory, monkeypatch, printer): ) ) assert result, "nothing found" - assert result[-1].path == expected_path, "not a latest version of Pype 2" + assert result[-1].path == expected_path, ("not a latest version of " + "OpenPype 2") - result = fix_bootstrap.find_pype(e_path, include_zips=True) - assert result is not None, "no Pype version found" + result = fix_bootstrap.find_openpype(e_path, include_zips=True) + assert result is not None, "no OpenPype version found" expected_path = Path( e_path / "{}{}{}".format( test_versions_1[5].prefix, @@ -374,10 +384,11 @@ def test_find_pype(fix_bootstrap, tmp_path_factory, monkeypatch, printer): test_versions_1[5].suffix ) ) - assert result[-1].path == expected_path, "not a latest version of Pype 1" + assert result[-1].path == expected_path, ("not a latest version of " + "OpenPype 1") - result = fix_bootstrap.find_pype(dir_path, include_zips=True) - assert result is not None, "no Pype versions found" + result = fix_bootstrap.find_openpype(dir_path, include_zips=True) + assert result is not None, "no OpenPype versions found" expected_path = Path( dir_path / "{}{}{}".format( test_versions_4[0].prefix, @@ -385,4 +396,5 @@ def test_find_pype(fix_bootstrap, tmp_path_factory, monkeypatch, printer): test_versions_4[0].suffix ) ) - assert result[-1].path == expected_path, "not a latest version of Pype 4" + assert result[-1].path == expected_path, ("not a latest version of " + "OpenPype 4") diff --git a/tests/pype/lib/test_user_settings.py b/tests/openpype/lib/test_user_settings.py similarity index 95% rename from tests/pype/lib/test_user_settings.py rename to tests/openpype/lib/test_user_settings.py index 02342abbc9..2c58e1f35a 100644 --- a/tests/pype/lib/test_user_settings.py +++ b/tests/openpype/lib/test_user_settings.py @@ -1,5 +1,7 @@ +# -*- coding: utf-8 -*- +"""Test suite for User Settings.""" import pytest -from pype.lib import ( +from igniter.user_settings import ( IniSettingRegistry, JSONSettingRegistry, OpenPypeSecureRegistry @@ -9,9 +11,9 @@ import configparser @pytest.fixture -def secure_registry(tmpdir): +def secure_registry(): name = "pypetest_{}".format(str(uuid4())) - r = OpenPypeSecureRegistry(name, tmpdir) + r = OpenPypeSecureRegistry(name) yield r diff --git a/tools/build.ps1 b/tools/build.ps1 index 1fd01191af..566e40cb55 100644 --- a/tools/build.ps1 +++ b/tools/build.ps1 @@ -74,11 +74,19 @@ function Install-Poetry() { $art = @" -▒█▀▀▀█ █▀▀█ █▀▀ █▀▀▄ ▒█▀▀█ █░░█ █▀▀█ █▀▀ ▀█▀ ▀█▀ ▀█▀ -▒█░░▒█ █░░█ █▀▀ █░░█ ▒█▄▄█ █▄▄█ █░░█ █▀▀ ▒█░ ▒█░ ▒█░ -▒█▄▄▄█ █▀▀▀ ▀▀▀ ▀░░▀ ▒█░░░ ▄▄▄█ █▀▀▀ ▀▀▀ ▄█▄ ▄█▄ ▄█▄ - .---= [ by Pype Club ] =---. - https://openpype.io + . . .. . .. + _oOOP3OPP3Op_. . + .PPpo~· ·· ~2p. ·· ···· · · + ·Ppo · .pPO3Op.· · O:· · · · + .3Pp · oP3'· 'P33· · 4 ·· · · · ·· · · · + ·~OP 3PO· .Op3 : · ·· _____ _____ _____ + ·P3O · oP3oP3O3P' · · · · / /·/ /·/ / + O3:· O3p~ · ·:· · ·/____/·/____/ /____/ + 'P · 3p3· oP3~· ·.P:· · · ·· · · ·· · · · + · ': · Po' ·Opo'· .3O· . o[ by Pype Club ]]]==- - - · · + · '_ .. · . _OP3·· · ·https://openpype.io·· · + ~P3·OPPPO3OP~ · ·· · + · ' '· · ·· · · · ·· · "@ diff --git a/tools/build.sh b/tools/build.sh index 62aecd8ee1..953d51bd81 100755 --- a/tools/build.sh +++ b/tools/build.sh @@ -6,11 +6,19 @@ art () { cat <<-EOF -▒█▀▀▀█ █▀▀█ █▀▀ █▀▀▄ ▒█▀▀█ █░░█ █▀▀█ █▀▀ ▀█▀ ▀█▀ ▀█▀ -▒█░░▒█ █░░█ █▀▀ █░░█ ▒█▄▄█ █▄▄█ █░░█ █▀▀ ▒█░ ▒█░ ▒█░ -▒█▄▄▄█ █▀▀▀ ▀▀▀ ▀░░▀ ▒█░░░ ▄▄▄█ █▀▀▀ ▀▀▀ ▄█▄ ▄█▄ ▄█▄ - .---= [ by Pype Club ] =---. - https://openpype.io + . . .. . .. + _oOOP3OPP3Op_. . + .PPpo~· ·· ~2p. ·· ···· · · + ·Ppo · .pPO3Op.· · O:· · · · + .3Pp · oP3'· 'P33· · 4 ·· · · · ·· · · · + ·~OP 3PO· .Op3 : · ·· _____ _____ _____ + ·P3O · oP3oP3O3P' · · · · / /·/ /·/ / + O3:· O3p~ · ·:· · ·/____/·/____/ /____/ + 'P · 3p3· oP3~· ·.P:· · · ·· · · ·· · · · + · ': · Po' ·Opo'· .3O· . o[ by Pype Club ]]]==- - - · · + · '_ .. · . _OP3·· · ·https://openpype.io·· · + ~P3·OPPPO3OP~ · ·· · + · ' '· · ·· · · · ·· · EOF } @@ -65,7 +73,7 @@ detect_python () { local version_command version_command="import sys;print('{0}.{1}'.format(sys.version_info[0], sys.version_info[1]))" local python_version - python_version="$(python3 <<< ${version_command})" + python_version="$(python <<< ${version_command})" oIFS="$IFS" IFS=. set -- $python_version @@ -77,7 +85,7 @@ detect_python () { echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}" fi else - command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}$1.$2$ - ${BIRed}FAILED${RST} ${BIYellow}Version is old and unsupported${RST}"; return 1; } + command -v python >/dev/null 2>&1 || { echo -e "${BIRed}$1.$2$ - ${BIRed}FAILED${RST} ${BIYellow}Version is old and unsupported${RST}"; return 1; } fi } @@ -123,7 +131,7 @@ realpath () { install_poetry () { echo -e "${BIGreen}>>>${RST} Installing Poetry ..." command -v curl >/dev/null 2>&1 || { echo -e "${BIRed}!!!${RST}${BIYellow} Missing ${RST}${BIBlue}curl${BIYellow} command.${RST}"; return 1; } - curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python3 - + curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python - } # Main @@ -138,7 +146,7 @@ main () { pushd "$openpype_root" > /dev/null || return > /dev/null version_command="import os;exec(open(os.path.join('$openpype_root', 'openpype', 'version.py')).read());print(__version__);" - openpype_version="$(python3 <<< ${version_command})" + openpype_version="$(python <<< ${version_command})" _inside_openpype_tool="1" @@ -169,11 +177,11 @@ main () { echo -e "${BIGreen}>>>${RST} Building ..." if [[ "$OSTYPE" == "linux-gnu"* ]]; then - poetry run python3 "$openpype_root/setup.py" build > "$openpype_root/build/build.log" || { echo -e "${BIRed}!!!${RST} Build failed, see the build log."; return; } + poetry run python "$openpype_root/setup.py" build > "$openpype_root/build/build.log" || { echo -e "${BIRed}!!!${RST} Build failed, see the build log."; return; } elif [[ "$OSTYPE" == "darwin"* ]]; then - poetry run python3 "$openpype_root/setup.py" bdist_mac > "$openpype_root/build/build.log" || { echo -e "${BIRed}!!!${RST} Build failed, see the build log."; return; } + poetry run python "$openpype_root/setup.py" bdist_mac > "$openpype_root/build/build.log" || { echo -e "${BIRed}!!!${RST} Build failed, see the build log."; return; } fi - poetry run python3 "$openpype_root/tools/build_dependencies.py" + poetry run python "$openpype_root/tools/build_dependencies.py" if [[ "$OSTYPE" == "darwin"* ]]; then # fix code signing issue diff --git a/tools/create_env.ps1 b/tools/create_env.ps1 index c806fc5e49..5600ae71c7 100644 --- a/tools/create_env.ps1 +++ b/tools/create_env.ps1 @@ -95,11 +95,21 @@ Set-Location -Path $openpype_root $art = @" -▒█▀▀▀█ █▀▀█ █▀▀ █▀▀▄ ▒█▀▀█ █░░█ █▀▀█ █▀▀ ▀█▀ ▀█▀ ▀█▀ -▒█░░▒█ █░░█ █▀▀ █░░█ ▒█▄▄█ █▄▄█ █░░█ █▀▀ ▒█░ ▒█░ ▒█░ -▒█▄▄▄█ █▀▀▀ ▀▀▀ ▀░░▀ ▒█░░░ ▄▄▄█ █▀▀▀ ▀▀▀ ▄█▄ ▄█▄ ▄█▄ - .---= [ by Pype Club ] =---. - https://openpype.io + + . . .. . .. + _oOOP3OPP3Op_. . + .PPpo~· ·· ~2p. ·· ···· · · + ·Ppo · .pPO3Op.· · O:· · · · + .3Pp · oP3'· 'P33· · 4 ·· · · · ·· · · · + ·~OP 3PO· .Op3 : · ·· _____ _____ _____ + ·P3O · oP3oP3O3P' · · · · / /·/ /·/ / + O3:· O3p~ · ·:· · ·/____/·/____/ /____/ + 'P · 3p3· oP3~· ·.P:· · · ·· · · ·· · · · + · ': · Po' ·Opo'· .3O· . o[ by Pype Club ]]]==- - - · · + · '_ .. · . _OP3·· · ·https://openpype.io·· · + ~P3·OPPPO3OP~ · ·· · + · ' '· · ·· · · · ·· · + "@ if (-not (Test-Path 'env:_INSIDE_OPENPYPE_TOOL')) { diff --git a/tools/create_env.sh b/tools/create_env.sh index 76597bc30e..d6a6828718 100755 --- a/tools/create_env.sh +++ b/tools/create_env.sh @@ -7,11 +7,19 @@ art () { cat <<-EOF -▒█▀▀▀█ █▀▀█ █▀▀ █▀▀▄ ▒█▀▀█ █░░█ █▀▀█ █▀▀ ▀█▀ ▀█▀ ▀█▀ -▒█░░▒█ █░░█ █▀▀ █░░█ ▒█▄▄█ █▄▄█ █░░█ █▀▀ ▒█░ ▒█░ ▒█░ -▒█▄▄▄█ █▀▀▀ ▀▀▀ ▀░░▀ ▒█░░░ ▄▄▄█ █▀▀▀ ▀▀▀ ▄█▄ ▄█▄ ▄█▄ - .---= [ by Pype Club ] =---. - https://openpype.io + . . .. . .. + _oOOP3OPP3Op_. . + .PPpo~· ·· ~2p. ·· ···· · · + ·Ppo · .pPO3Op.· · O:· · · · + .3Pp · oP3'· 'P33· · 4 ·· · · · ·· · · · + ·~OP 3PO· .Op3 : · ·· _____ _____ _____ + ·P3O · oP3oP3O3P' · · · · / /·/ /·/ / + O3:· O3p~ · ·:· · ·/____/·/____/ /____/ + 'P · 3p3· oP3~· ·.P:· · · ·· · · ·· · · · + · ': · Po' ·Opo'· .3O· . o[ by Pype Club ]]]==- - - · · + · '_ .. · . _OP3·· · ·https://openpype.io·· · + ~P3·OPPPO3OP~ · ·· · + · ' '· · ·· · · · ·· · EOF } @@ -81,7 +89,7 @@ done detect_python () { echo -e "${BIGreen}>>>${RST} Using python \c" local version_command="import sys;print('{0}.{1}'.format(sys.version_info[0], sys.version_info[1]))" - local python_version="$(python3 <<< ${version_command})" + local python_version="$(python <<< ${version_command})" oIFS="$IFS" IFS=. set -- $python_version @@ -93,15 +101,16 @@ detect_python () { echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}" fi else - command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}$1.$2$ - ${BIRed}FAILED${RST} ${BIYellow}Version is old and unsupported${RST}"; return 1; } + command -v python >/dev/null 2>&1 || { echo -e "${BIRed}$1.$2$ - ${BIRed}FAILED${RST} ${BIYellow}Version is old and unsupported${RST}"; return 1; } fi } install_poetry () { echo -e "${BIGreen}>>>${RST} Installing Poetry ..." + export POETRY_HOME="$openpype_root/.poetry" command -v curl >/dev/null 2>&1 || { echo -e "${BIRed}!!!${RST}${BIYellow} Missing ${RST}${BIBlue}curl${BIYellow} command.${RST}"; return 1; } - curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python3 - - export PATH="$PATH:$HOME/.poetry/bin" + curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python - + export PATH="$PATH:$POETRY_HOME/bin" } ############################################################################## @@ -177,7 +186,7 @@ main () { # cx_freeze will crash on missing __pychache__ on these but # reinstalling them solves the problem. echo -e "${BIGreen}>>>${RST} Fixing pycache bug ..." - poetry run python -m pip install --upgrade pip + poetry run python -m pip install --force-reinstall pip poetry run pip install --force-reinstall setuptools poetry run pip install --force-reinstall wheel poetry run python -m pip install --force-reinstall pip diff --git a/tools/create_zip.ps1 b/tools/create_zip.ps1 index 4ccfd949fe..2fef4d216b 100644 --- a/tools/create_zip.ps1 +++ b/tools/create_zip.ps1 @@ -50,11 +50,19 @@ Set-Location -Path $openpype_root $art = @" -▒█▀▀▀█ █▀▀█ █▀▀ █▀▀▄ ▒█▀▀█ █░░█ █▀▀█ █▀▀ ▀█▀ ▀█▀ ▀█▀ -▒█░░▒█ █░░█ █▀▀ █░░█ ▒█▄▄█ █▄▄█ █░░█ █▀▀ ▒█░ ▒█░ ▒█░ -▒█▄▄▄█ █▀▀▀ ▀▀▀ ▀░░▀ ▒█░░░ ▄▄▄█ █▀▀▀ ▀▀▀ ▄█▄ ▄█▄ ▄█▄ - .---= [ by Pype Club ] =---. - https://openpype.io + . . .. . .. + _oOOP3OPP3Op_. . + .PPpo~· ·· ~2p. ·· ···· · · + ·Ppo · .pPO3Op.· · O:· · · · + .3Pp · oP3'· 'P33· · 4 ·· · · · ·· · · · + ·~OP 3PO· .Op3 : · ·· _____ _____ _____ + ·P3O · oP3oP3O3P' · · · · / /·/ /·/ / + O3:· O3p~ · ·:· · ·/____/·/____/ /____/ + 'P · 3p3· oP3~· ·.P:· · · ·· · · ·· · · · + · ': · Po' ·Opo'· .3O· . o[ by Pype Club ]]]==- - - · · + · '_ .. · . _OP3·· · ·https://openpype.io·· · + ~P3·OPPPO3OP~ · ·· · + · ' '· · ·· · · · ·· · "@ diff --git a/tools/create_zip.sh b/tools/create_zip.sh index 030039aa92..adaf9431a7 100755 --- a/tools/create_zip.sh +++ b/tools/create_zip.sh @@ -8,11 +8,19 @@ art () { cat <<-EOF -▒█▀▀▀█ █▀▀█ █▀▀ █▀▀▄ ▒█▀▀█ █░░█ █▀▀█ █▀▀ ▀█▀ ▀█▀ ▀█▀ -▒█░░▒█ █░░█ █▀▀ █░░█ ▒█▄▄█ █▄▄█ █░░█ █▀▀ ▒█░ ▒█░ ▒█░ -▒█▄▄▄█ █▀▀▀ ▀▀▀ ▀░░▀ ▒█░░░ ▄▄▄█ █▀▀▀ ▀▀▀ ▄█▄ ▄█▄ ▄█▄ - .---= [ by Pype Club ] =---. - https://openpype.io + . . .. . .. + _oOOP3OPP3Op_. . + .PPpo~· ·· ~2p. ·· ···· · · + ·Ppo · .pPO3Op.· · O:· · · · + .3Pp · oP3'· 'P33· · 4 ·· · · · ·· · · · + ·~OP 3PO· .Op3 : · ·· _____ _____ _____ + ·P3O · oP3oP3O3P' · · · · / /·/ /·/ / + O3:· O3p~ · ·:· · ·/____/·/____/ /____/ + 'P · 3p3· oP3~· ·.P:· · · ·· · · ·· · · · + · ': · Po' ·Opo'· .3O· . o[ by Pype Club ]]]==- - - · · + · '_ .. · . _OP3·· · ·https://openpype.io·· · + ~P3·OPPPO3OP~ · ·· · + · ' '· · ·· · · · ·· · EOF } diff --git a/tools/docker_build.sh b/tools/docker_build.sh new file mode 100755 index 0000000000..7600fe044b --- /dev/null +++ b/tools/docker_build.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash + +# Colors for terminal + +RST='\033[0m' # Text Reset +BIGreen='\033[1;92m' # Green +BIYellow='\033[1;93m' # Yellow +BIRed='\033[1;91m' # Red + +############################################################################## +# Return absolute path +# Globals: +# None +# Arguments: +# Path to resolve +# Returns: +# None +############################################################################### +realpath () { + echo $(cd $(dirname "$1"); pwd)/$(basename "$1") +} + +# Main +main () { + openpype_root=$(realpath $(dirname $(dirname "${BASH_SOURCE[0]}"))) + pushd "$openpype_root" > /dev/null || return > /dev/null + + echo -e "${BIYellow}---${RST} Cleaning build directory ..." + rm -rf "$openpype_root/build" && mkdir "$openpype_root/build" > /dev/null + + version_command="import os;exec(open(os.path.join('$openpype_root', 'openpype', 'version.py')).read());print(__version__);" + openpype_version="$(python3 <<< ${version_command})" + + echo -e "${BIGreen}>>>${RST} Running docker build ..." + docker build --pull --no-cache -t pypeclub/openpype:$openpype_version . + if [ $? -ne 0 ] ; then + echo -e "${BIRed}!!!${RST} Docker build failed." + return 1 + fi + + echo -e "${BIGreen}>>>${RST} Copying build from container ..." + echo -e "${BIYellow}---${RST} Creating container from pypeclub/openpype:$openpype_version ..." + id="$(docker create -ti pypeclub/openpype:$openpype_version bash)" + if [ $? -ne 0 ] ; then + echo -e "${BIRed}!!!${RST} Cannot create just built container." + return 1 + fi + echo -e "${BIYellow}---${RST} Copying ..." + docker cp "$id:/opt/openpype/build/exe.linux-x86_64-3.7" "$openpype_root/build" + if [ $? -ne 0 ] ; then + echo -e "${BIRed}!!!${RST} Copying failed." + return 1 + fi + + echo -e "${BIGreen}>>>${RST} Fixing user ownership ..." + username="$(logname)" + chown -R $username ./build + + echo -e "${BIGreen}>>>${RST} All done, you can delete container:" + echo -e "${BIYellow}$id${RST}" +} + +return_code=0 +main || return_code=$? +exit $return_code diff --git a/tools/fetch_thirdparty_libs.sh b/tools/fetch_thirdparty_libs.sh index 3875541d57..31f109ba68 100755 --- a/tools/fetch_thirdparty_libs.sh +++ b/tools/fetch_thirdparty_libs.sh @@ -5,13 +5,20 @@ art () { cat <<-EOF - ____________ - /\\ ___ \\ - \\ \\ \\/_\\ \\ - \\ \\ _____/ ______ ___ ___ ___ - \\ \\ \\___/ /\\ \\ \\ \\\\ \\\\ \\ - \\ \\____\\ \\ \\_____\\ \\__\\\\__\\\\__\\ - \\/____/ \\/_____/ . PYPE Club . + + . . .. . .. + _oOOP3OPP3Op_. . + .PPpo~· ·· ~2p. ·· ···· · · + ·Ppo · .pPO3Op.· · O:· · · · + .3Pp · oP3'· 'P33· · 4 ·· · · · ·· · · · + ·~OP 3PO· .Op3 : · ·· _____ _____ _____ + ·P3O · oP3oP3O3P' · · · · / /·/ /·/ / + O3:· O3p~ · ·:· · ·/____/·/____/ /____/ + 'P · 3p3· oP3~· ·.P:· · · ·· · · ·· · · · + · ': · Po' ·Opo'· .3O· . o[ by Pype Club ]]]==- - - · · + · '_ .. · . _OP3·· · ·https://openpype.io·· · + ~P3·OPPPO3OP~ · ·· · + · ' '· · ·· · · · ·· · EOF } @@ -51,53 +58,6 @@ BICyan='\033[1;96m' # Cyan BIWhite='\033[1;97m' # White -############################################################################## -# Detect required version of python -# Globals: -# colors -# PYTHON -# Arguments: -# None -# Returns: -# None -############################################################################### -detect_python () { - echo -e "${BIGreen}>>>${RST} Using python \c" - local version_command="import sys;print('{0}.{1}'.format(sys.version_info[0], sys.version_info[1]))" - local python_version="$(python3 <<< ${version_command})" - oIFS="$IFS" - IFS=. - set -- $python_version - IFS="$oIFS" - if [ "$1" -ge "3" ] && [ "$2" -ge "6" ] ; then - if [ "$2" -gt "7" ] ; then - echo -e "${BIWhite}[${RST} ${BIRed}$1.$2 ${BIWhite}]${RST} - ${BIRed}FAILED${RST} ${BIYellow}Version is new and unsupported, use${RST} ${BIPurple}3.7.x${RST}"; return 1; - else - echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}" - fi - PYTHON="python3" - else - command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}$1.$2$ - ${BIRed}FAILED${RST} ${BIYellow}Version is old and unsupported${RST}"; return 1; } - fi -} - -############################################################################## -# Clean pyc files in specified directory -# Globals: -# None -# Arguments: -# Optional path to clean -# Returns: -# None -############################################################################### -clean_pyc () { - local path - path=$pype_root - echo -e "${BIGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c" - find "$path" -regex '^.*\(__pycache__\|\.py[co]\)$' -delete - echo -e "${BIGreen}DONE${RST}" -} - ############################################################################## # Return absolute path # Globals: @@ -140,7 +100,7 @@ main () { pushd "$openpype_root" > /dev/null || return > /dev/null echo -e "${BIGreen}>>>${RST} Running Pype tool ..." - poetry run python3 "$openpype_root/tools/fetch_thirdparty_libs.py" + poetry run python "$openpype_root/tools/fetch_thirdparty_libs.py" } main \ No newline at end of file diff --git a/tools/make_docs.ps1 b/tools/make_docs.ps1 index f0ccaae004..01edaf9c58 100644 --- a/tools/make_docs.ps1 +++ b/tools/make_docs.ps1 @@ -30,12 +30,19 @@ Set-Location -Path $openpype_root $art = @" - -▒█▀▀▀█ █▀▀█ █▀▀ █▀▀▄ ▒█▀▀█ █░░█ █▀▀█ █▀▀ ▀█▀ ▀█▀ ▀█▀ -▒█░░▒█ █░░█ █▀▀ █░░█ ▒█▄▄█ █▄▄█ █░░█ █▀▀ ▒█░ ▒█░ ▒█░ -▒█▄▄▄█ █▀▀▀ ▀▀▀ ▀░░▀ ▒█░░░ ▄▄▄█ █▀▀▀ ▀▀▀ ▄█▄ ▄█▄ ▄█▄ - .---= [ by Pype Club ] =---. - https://openpype.io + . . .. . .. + _oOOP3OPP3Op_. . + .PPpo~· ·· ~2p. ·· ···· · · + ·Ppo · .pPO3Op.· · O:· · · · + .3Pp · oP3'· 'P33· · 4 ·· · · · ·· · · · + ·~OP 3PO· .Op3 : · ·· _____ _____ _____ + ·P3O · oP3oP3O3P' · · · · / /·/ /·/ / + O3:· O3p~ · ·:· · ·/____/·/____/ /____/ + 'P · 3p3· oP3~· ·.P:· · · ·· · · ·· · · · + · ': · Po' ·Opo'· .3O· . o[ by Pype Club ]]]==- - - · · + · '_ .. · . _OP3·· · ·https://openpype.io·· · + ~P3·OPPPO3OP~ · ·· · + · ' '· · ·· · · · ·· · "@ diff --git a/tools/make_docs.sh b/tools/make_docs.sh index edd29a4c6c..9dfab26a38 100755 --- a/tools/make_docs.sh +++ b/tools/make_docs.sh @@ -7,11 +7,20 @@ art () { cat <<-EOF -▒█▀▀▀█ █▀▀█ █▀▀ █▀▀▄ ▒█▀▀█ █░░█ █▀▀█ █▀▀ ▀█▀ ▀█▀ ▀█▀ -▒█░░▒█ █░░█ █▀▀ █░░█ ▒█▄▄█ █▄▄█ █░░█ █▀▀ ▒█░ ▒█░ ▒█░ -▒█▄▄▄█ █▀▀▀ ▀▀▀ ▀░░▀ ▒█░░░ ▄▄▄█ █▀▀▀ ▀▀▀ ▄█▄ ▄█▄ ▄█▄ - .---= [ by Pype Club ] =---. - https://openpype.io + . . .. . .. + _oOOP3OPP3Op_. . + .PPpo~· ·· ~2p. ·· ···· · · + ·Ppo · .pPO3Op.· · O:· · · · + .3Pp · oP3'· 'P33· · 4 ·· · · · ·· · · · + ·~OP 3PO· .Op3 : · ·· _____ _____ _____ + ·P3O · oP3oP3O3P' · · · · / /·/ /·/ / + O3:· O3p~ · ·:· · ·/____/·/____/ /____/ + 'P · 3p3· oP3~· ·.P:· · · ·· · · ·· · · · + · ': · Po' ·Opo'· .3O· . o[ by Pype Club ]]]==- - - · · + · '_ .. · . _OP3·· · ·https://openpype.io·· · + ~P3·OPPPO3OP~ · ·· · + · ' '· · ·· · · · ·· · + EOF } diff --git a/tools/run_mongo.ps1 b/tools/run_mongo.ps1 index 7e43a355e5..05fc497d34 100644 --- a/tools/run_mongo.ps1 +++ b/tools/run_mongo.ps1 @@ -13,11 +13,19 @@ PS> .\run_mongo.ps1 $art = @" -▒█▀▀▀█ █▀▀█ █▀▀ █▀▀▄ ▒█▀▀█ █░░█ █▀▀█ █▀▀ ▀█▀ ▀█▀ ▀█▀ -▒█░░▒█ █░░█ █▀▀ █░░█ ▒█▄▄█ █▄▄█ █░░█ █▀▀ ▒█░ ▒█░ ▒█░ -▒█▄▄▄█ █▀▀▀ ▀▀▀ ▀░░▀ ▒█░░░ ▄▄▄█ █▀▀▀ ▀▀▀ ▄█▄ ▄█▄ ▄█▄ - .---= [ by Pype Club ] =---. - https://openpype.io + . . .. . .. + _oOOP3OPP3Op_. . + .PPpo~· ·· ~2p. ·· ···· · · + ·Ppo · .pPO3Op.· · O:· · · · + .3Pp · oP3'· 'P33· · 4 ·· · · · ·· · · · + ·~OP 3PO· .Op3 : · ·· _____ _____ _____ + ·P3O · oP3oP3O3P' · · · · / /·/ /·/ / + O3:· O3p~ · ·:· · ·/____/·/____/ /____/ + 'P · 3p3· oP3~· ·.P:· · · ·· · · ·· · · · + · ': · Po' ·Opo'· .3O· . o[ by Pype Club ]]]==- - - · · + · '_ .. · . _OP3·· · ·https://openpype.io·· · + ~P3·OPPPO3OP~ · ·· · + · ' '· · ·· · · · ·· · "@ diff --git a/tools/run_mongo.sh b/tools/run_mongo.sh index 8c94fcf881..7b512e67ab 100755 --- a/tools/run_mongo.sh +++ b/tools/run_mongo.sh @@ -7,11 +7,19 @@ art () { cat <<-EOF -▒█▀▀▀█ █▀▀█ █▀▀ █▀▀▄ ▒█▀▀█ █░░█ █▀▀█ █▀▀ ▀█▀ ▀█▀ ▀█▀ -▒█░░▒█ █░░█ █▀▀ █░░█ ▒█▄▄█ █▄▄█ █░░█ █▀▀ ▒█░ ▒█░ ▒█░ -▒█▄▄▄█ █▀▀▀ ▀▀▀ ▀░░▀ ▒█░░░ ▄▄▄█ █▀▀▀ ▀▀▀ ▄█▄ ▄█▄ ▄█▄ - .---= [ by Pype Club ] =---. - https://openpype.io + . . .. . .. + _oOOP3OPP3Op_. . + .PPpo~· ·· ~2p. ·· ···· · · + ·Ppo · .pPO3Op.· · O:· · · · + .3Pp · oP3'· 'P33· · 4 ·· · · · ·· · · · + ·~OP 3PO· .Op3 : · ·· _____ _____ _____ + ·P3O · oP3oP3O3P' · · · · / /·/ /·/ / + O3:· O3p~ · ·:· · ·/____/·/____/ /____/ + 'P · 3p3· oP3~· ·.P:· · · ·· · · ·· · · · + · ': · Po' ·Opo'· .3O· . o[ by Pype Club ]]]==- - - · · + · '_ .. · . _OP3·· · ·https://openpype.io·· · + ~P3·OPPPO3OP~ · ·· · + · ' '· · ·· · · · ·· · EOF } diff --git a/tools/run_settings.sh b/tools/run_settings.sh index 2e1dfc744f..0287043bb6 100755 --- a/tools/run_settings.sh +++ b/tools/run_settings.sh @@ -6,11 +6,19 @@ art () { cat <<-EOF -▒█▀▀▀█ █▀▀█ █▀▀ █▀▀▄ ▒█▀▀█ █░░█ █▀▀█ █▀▀ ▀█▀ ▀█▀ ▀█▀ -▒█░░▒█ █░░█ █▀▀ █░░█ ▒█▄▄█ █▄▄█ █░░█ █▀▀ ▒█░ ▒█░ ▒█░ -▒█▄▄▄█ █▀▀▀ ▀▀▀ ▀░░▀ ▒█░░░ ▄▄▄█ █▀▀▀ ▀▀▀ ▄█▄ ▄█▄ ▄█▄ - .---= [ by Pype Club ] =---. - https://openpype.io + . . .. . .. + _oOOP3OPP3Op_. . + .PPpo~· ·· ~2p. ·· ···· · · + ·Ppo · .pPO3Op.· · O:· · · · + .3Pp · oP3'· 'P33· · 4 ·· · · · ·· · · · + ·~OP 3PO· .Op3 : · ·· _____ _____ _____ + ·P3O · oP3oP3O3P' · · · · / /·/ /·/ / + O3:· O3p~ · ·:· · ·/____/·/____/ /____/ + 'P · 3p3· oP3~· ·.P:· · · ·· · · ·· · · · + · ': · Po' ·Opo'· .3O· . o[ by Pype Club ]]]==- - - · · + · '_ .. · . _OP3·· · ·https://openpype.io·· · + ~P3·OPPPO3OP~ · ·· · + · ' '· · ·· · · · ·· · EOF } @@ -50,23 +58,6 @@ BICyan='\033[1;96m' # Cyan BIWhite='\033[1;97m' # White -############################################################################## -# Clean pyc files in specified directory -# Globals: -# None -# Arguments: -# Optional path to clean -# Returns: -# None -############################################################################### -clean_pyc () { - local path - path=$openpype_root - echo -e "${BIGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c" - find "$path" -regex '^.*\(__pycache__\|\.py[co]\)$' -delete - echo -e "${BIGreen}DONE${RST}" -} - ############################################################################## # Return absolute path # Globals: @@ -82,9 +73,6 @@ realpath () { # Main main () { - echo -e "${BGreen}" - art - echo -e "${RST}" # Directories openpype_root=$(realpath $(dirname $(dirname "${BASH_SOURCE[0]}"))) diff --git a/tools/run_tests.ps1 b/tools/run_tests.ps1 index 15161adabe..7b9a5c841d 100644 --- a/tools/run_tests.ps1 +++ b/tools/run_tests.ps1 @@ -32,11 +32,19 @@ function Show-PSWarning() { $art = @" -▒█▀▀▀█ █▀▀█ █▀▀ █▀▀▄ ▒█▀▀█ █░░█ █▀▀█ █▀▀ ▀█▀ ▀█▀ ▀█▀ -▒█░░▒█ █░░█ █▀▀ █░░█ ▒█▄▄█ █▄▄█ █░░█ █▀▀ ▒█░ ▒█░ ▒█░ -▒█▄▄▄█ █▀▀▀ ▀▀▀ ▀░░▀ ▒█░░░ ▄▄▄█ █▀▀▀ ▀▀▀ ▄█▄ ▄█▄ ▄█▄ - .---= [ by Pype Club ] =---. - https://openpype.io + . . .. . .. + _oOOP3OPP3Op_. . + .PPpo~· ·· ~2p. ·· ···· · · + ·Ppo · .pPO3Op.· · O:· · · · + .3Pp · oP3'· 'P33· · 4 ·· · · · ·· · · · + ·~OP 3PO· .Op3 : · ·· _____ _____ _____ + ·P3O · oP3oP3O3P' · · · · / /·/ /·/ / + O3:· O3p~ · ·:· · ·/____/·/____/ /____/ + 'P · 3p3· oP3~· ·.P:· · · ·· · · ·· · · · + · ': · Po' ·Opo'· .3O· . o[ by Pype Club ]]]==- - - · · + · '_ .. · . _OP3·· · ·https://openpype.io·· · + ~P3·OPPPO3OP~ · ·· · + · ' '· · ·· · · · ·· · "@ diff --git a/tools/run_tests.sh b/tools/run_tests.sh index a161f479b5..3620ebc0e5 100755 --- a/tools/run_tests.sh +++ b/tools/run_tests.sh @@ -6,11 +6,19 @@ art () { cat <<-EOF -▒█▀▀▀█ █▀▀█ █▀▀ █▀▀▄ ▒█▀▀█ █░░█ █▀▀█ █▀▀ ▀█▀ ▀█▀ ▀█▀ -▒█░░▒█ █░░█ █▀▀ █░░█ ▒█▄▄█ █▄▄█ █░░█ █▀▀ ▒█░ ▒█░ ▒█░ -▒█▄▄▄█ █▀▀▀ ▀▀▀ ▀░░▀ ▒█░░░ ▄▄▄█ █▀▀▀ ▀▀▀ ▄█▄ ▄█▄ ▄█▄ - .---= [ by Pype Club ] =---. - https://openpype.io + . . .. . .. + _oOOP3OPP3Op_. . + .PPpo~· ·· ~2p. ·· ···· · · + ·Ppo · .pPO3Op.· · O:· · · · + .3Pp · oP3'· 'P33· · 4 ·· · · · ·· · · · + ·~OP 3PO· .Op3 : · ·· _____ _____ _____ + ·P3O · oP3oP3O3P' · · · · / /·/ /·/ / + O3:· O3p~ · ·:· · ·/____/·/____/ /____/ + 'P · 3p3· oP3~· ·.P:· · · ·· · · ·· · · · + · ': · Po' ·Opo'· .3O· . o[ by Pype Club ]]]==- - - · · + · '_ .. · . _OP3·· · ·https://openpype.io·· · + ~P3·OPPPO3OP~ · ·· · + · ' '· · ·· · · · ·· · EOF } @@ -114,5 +122,4 @@ main () { PYTHONPATH=$original_pythonpath } - - +main diff --git a/tools/run_tray.sh b/tools/run_tray.sh index 7471d3ca5a..339ff6f918 100755 --- a/tools/run_tray.sh +++ b/tools/run_tray.sh @@ -1,20 +1,6 @@ #!/usr/bin/env bash - # Run OpenPype Tray - -art () { - cat <<-EOF - -▒█▀▀▀█ █▀▀█ █▀▀ █▀▀▄ ▒█▀▀█ █░░█ █▀▀█ █▀▀ ▀█▀ ▀█▀ ▀█▀ -▒█░░▒█ █░░█ █▀▀ █░░█ ▒█▄▄█ █▄▄█ █░░█ █▀▀ ▒█░ ▒█░ ▒█░ -▒█▄▄▄█ █▀▀▀ ▀▀▀ ▀░░▀ ▒█░░░ ▄▄▄█ █▀▀▀ ▀▀▀ ▄█▄ ▄█▄ ▄█▄ - .---= [ by Pype Club ] =---. - https://openpype.io - -EOF -} - # Colors for terminal RST='\033[0m' # Text Reset @@ -49,22 +35,6 @@ BIPurple='\033[1;95m' # Purple BICyan='\033[1;96m' # Cyan BIWhite='\033[1;97m' # White -############################################################################## -# Clean pyc files in specified directory -# Globals: -# None -# Arguments: -# Optional path to clean -# Returns: -# None -############################################################################### -clean_pyc () { - local path - path=$openpype_root - echo -e "${BIGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c" - find "$path" -regex '^.*\(__pycache__\|\.py[co]\)$' -delete - echo -e "${BIGreen}DONE${RST}" -} ############################################################################## # Return absolute path @@ -81,11 +51,6 @@ realpath () { # Main main () { - echo -e "${BGreen}" - art - echo -e "${RST}" - detect_python || return 1 - # Directories openpype_root=$(realpath $(dirname $(dirname "${BASH_SOURCE[0]}"))) diff --git a/tools/update_submodules.ps1 b/tools/update_submodules.ps1 index d0f93d9f7e..8ecc278510 100644 --- a/tools/update_submodules.ps1 +++ b/tools/update_submodules.ps1 @@ -10,11 +10,19 @@ PS> .\update_submodules.ps1 $art = @" -▒█▀▀▀█ █▀▀█ █▀▀ █▀▀▄ ▒█▀▀█ █░░█ █▀▀█ █▀▀ ▀█▀ ▀█▀ ▀█▀ -▒█░░▒█ █░░█ █▀▀ █░░█ ▒█▄▄█ █▄▄█ █░░█ █▀▀ ▒█░ ▒█░ ▒█░ -▒█▄▄▄█ █▀▀▀ ▀▀▀ ▀░░▀ ▒█░░░ ▄▄▄█ █▀▀▀ ▀▀▀ ▄█▄ ▄█▄ ▄█▄ - .---= [ by Pype Club ] =---. - https://openpype.io + . . .. . .. + _oOOP3OPP3Op_. . + .PPpo~· ·· ~2p. ·· ···· · · + ·Ppo · .pPO3Op.· · O:· · · · + .3Pp · oP3'· 'P33· · 4 ·· · · · ·· · · · + ·~OP 3PO· .Op3 : · ·· _____ _____ _____ + ·P3O · oP3oP3O3P' · · · · / /·/ /·/ / + O3:· O3p~ · ·:· · ·/____/·/____/ /____/ + 'P · 3p3· oP3~· ·.P:· · · ·· · · ·· · · · + · ': · Po' ·Opo'· .3O· . o[ by Pype Club ]]]==- - - · · + · '_ .. · . _OP3·· · ·https://openpype.io·· · + ~P3·OPPPO3OP~ · ·· · + · ' '· · ·· · · · ·· · "@ diff --git a/tools/update_submodules.sh b/tools/update_submodules.sh index 465827bfbb..49a3d08afb 100644 --- a/tools/update_submodules.sh +++ b/tools/update_submodules.sh @@ -6,10 +6,19 @@ art () { cat <<-EOF -▒█▀▀▀█ █▀▀█ █▀▀ █▀▀▄ ▒█▀▀█ █░░█ █▀▀█ █▀▀ ▀█▀ ▀█▀ ▀█▀ -▒█░░▒█ █░░█ █▀▀ █░░█ ▒█▄▄█ █▄▄█ █░░█ █▀▀ ▒█░ ▒█░ ▒█░ -▒█▄▄▄█ █▀▀▀ ▀▀▀ ▀░░▀ ▒█░░░ ▄▄▄█ █▀▀▀ ▀▀▀ ▄█▄ ▄█▄ ▄█▄ - .---= [ by Pype Club ] =---. + . . .. . .. + _oOOP3OPP3Op_. . + .PPpo~· ·· ~2p. ·· ···· · · + ·Ppo · .pPO3Op.· · O:· · · · + .3Pp · oP3'· 'P33· · 4 ·· · · · ·· · · · + ·~OP 3PO· .Op3 : · ·· _____ _____ _____ + ·P3O · oP3oP3O3P' · · · · / /·/ /·/ / + O3:· O3p~ · ·:· · ·/____/·/____/ /____/ + 'P · 3p3· oP3~· ·.P:· · · ·· · · ·· · · · + · ': · Po' ·Opo'· .3O· . o[ by Pype Club ]]]==- - - · · + · '_ .. · . _OP3·· · ·https://openpype.io·· · + ~P3·OPPPO3OP~ · ·· · + · ' '· · ·· · · · ·· · EOF } diff --git a/website/docs/admin_hosts_aftereffects.md b/website/docs/admin_hosts_aftereffects.md new file mode 100644 index 0000000000..dc43820465 --- /dev/null +++ b/website/docs/admin_hosts_aftereffects.md @@ -0,0 +1,39 @@ +--- +id: admin_hosts_aftereffects +title: AfterEffects Settings +sidebar_label: AfterEffects +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +## AfterEffects settings + +There is a couple of settings that could configure publishing process for **AfterEffects**. +All of them are Project based, eg. each project could have different configuration. + +Location: Settings > Project > AfterEffects + +![Harmony Project Settings](assets/admin_hosts_aftereffects_settings.png) + +## Publish plugins + +### Validate Scene Settings + +#### Skip Resolution Check for Tasks + +Set regex pattern(s) to look for in a Task name to skip resolution check against values from DB. + +#### Skip Timeline Check for Tasks + +Set regex pattern(s) to look for in a Task name to skip `frameStart`, `frameEnd` check against values from DB. + +### AfterEffects Submit to Deadline + +* `Use Published scene` - Set to True (green) when Deadline should take published scene as a source instead of uploaded local one. +* `Priority` - priority of job on farm +* `Primary Pool` - here is list of pool fetched from server you can select from. +* `Secondary Pool` +* `Frames Per Task` - number of sequence division between individual tasks (chunks) +making one job on farm. + diff --git a/website/docs/admin_hosts_resolve.md b/website/docs/admin_hosts_resolve.md new file mode 100644 index 0000000000..d2e027205d --- /dev/null +++ b/website/docs/admin_hosts_resolve.md @@ -0,0 +1,103 @@ +--- +id: admin_hosts_resolve +title: DaVinci Resolve Setup +sidebar_label: DaVinci Resolve +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +## Resolve requirements +Due to the way resolve handles python and python scripts there are a few steps required steps needed to be done on any machine that will be using OpenPype with resolve. + +### Installing Resolve's own python 3.6 interpreter. +Resolve uses a hardcoded method to look for the python executable path. All of tho following paths are defined automatically by Python msi installer. We are using Python 3.6.2. + + + + + +`%LOCALAPPDATA%\Programs\Python\Python36` + + + + +`/opt/Python/3.6/bin` + + + + +`~/Library/Python/3.6/bin` + + + + + +### Installing PySide2 into python 3.6 for correct gui work + +OpenPype is using its own window widget inside Resolve, for that reason PySide2 has to be installed into the python 3.6 (as explained above). + + + + + +paste to any terminal of your choice + +```bash +%LOCALAPPDATA%\Programs\Python\Python36\python.exe -m pip install PySide2 +``` + + + + +paste to any terminal of your choice + +```bash +/opt/Python/3.6/bin/python -m pip install PySide2 +``` + + + + +paste to any terminal of your choice + +```bash +~/Library/Python/3.6/bin/python -m pip install PySide2 +``` + + + + +
+ +### Set Resolve's Fusion settings for Python 3.6 interpereter + +
+ + +As it is shown in bellow picture you have to go to Fusion Tab and then in Fusion menu find Fusion Settings. Go to Fusion/Script and find Default Python Version and swith to Python 3.6 + +
+ +
+ +![Create menu](assets/resolve_fusion_tab.png) +![Create menu](assets/resolve_fusion_menu.png) +![Create menu](assets/resolve_fusion_script_settings.png) + +
+
\ No newline at end of file diff --git a/website/docs/artist_hosts_resolve.md b/website/docs/artist_hosts_resolve.md new file mode 100644 index 0000000000..be069eea79 --- /dev/null +++ b/website/docs/artist_hosts_resolve.md @@ -0,0 +1,216 @@ +--- +id: artist_hosts_resolve +title: DaVinci Resolve +sidebar_label: DaVinci Resolve +--- + + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +:::warning +Before you are able to start with OpenPype tools in DaVinci Resolve, installation of its own Python 3.6 interpreter and PySide 2 has to be done. Go to [Installation of python and pyside](#installation-of-python-and-pyside) link for more information +::: + + + +## OpenPype global tools + +- [Work Files](artist_tools.md#workfiles) +- [Create](artist_tools.md#creator) +- [Load](artist_tools.md#loader) +- [Manage (Inventory)](artist_tools.md#inventory) +- [Publish](artist_tools.md#publisher) + + +
+ +## Creating Shots from timeline items + +Before a clip can be published with [Publisher](artist_tools.md#publisher) timeline item has to be marked with OpenPype metadata markers. This way it is converted to a publishable subset. + +Lets do it step by step. + +
+ + +
+ +### Color clips before opening Create menu + + +Timeline video clips should be colored to `Chocolate` color for OpenPype to se it as selected for subset creation. + + +
+ +![Create menu](assets/resolve_select_clips_timeline_chocolate.png) + +
+
+ + +### Rename timeline track names + +
+ + +
+ +To be able to work with dynamic subset name, which is based on track names it is recommended to rename those tracks to what type of plates their clips represent. Commonly used ones are `main`, `review`, `fg01`, `fg02`, `bg`, `bg01`, etc. It is completely up to you but we recommend to always have at least `main` plate. For example if a clip is on track **element** and subset family is set to **plate** then the resulting subset name will be **plateElement** + +

+
+ +
+ +![Create menu](assets/resolve_creator_subset_name.png) +The name of the resulting *subset* can be seen in the **OpenPypeData** marker. +



+
+ +
+ +![Create menu](assets/resolve_remame_track_names.png) +Simple track setup where we are only using `main` and `review` track names. + +
+
+ +![Create menu](assets/resolve_create_vertical_rename_timeline.png) +An example of used track names. The yellow frame is highlighting vertically aligned clips - which are going to be renamed and grouped together under one asset (shot) name. The concept of vertical renaming will be explained later in [Vertical Synchronization of Subset Attributes](#vertical-synchronization-of-subset-attributes). + +
+
+ + +### Create menu... + +
+
+ +After all clips which are intended to be converted to publishable instances are colored to `Chocolate` color, you can open OpenPype menu. + +
+
+ +![Create menu](assets/resolve_menu_openpype.png) + +
+ +
+ +
+
+ +After the menu widget is opened (it can take while so be patient please :). + +Hit `Create ...` and then set **Use selection** to active and select the family to **Create Publishable Clips**. + +The Subset name can stay as it is, it is not going to be used because each clip will generate it's own name. + +
+
+ +![Create menu](assets/resolve_create_clips.png) + +
+
+ +
+
+ +The new windows that opens, let's you define various attributes for your future subsets and shots. + +Set Rename clips to active if you wish to use different names of shots in pipeline then the original clip names conformed from EDL/XML. + +**Count sequence from** - Start of the shot numbering if `#` is used in one of the keywords + +**Stepping number** - Sequential gaps in the numbering + +As you can see the in `{shot}` key within *Shot Template Keywords* section, you can use `#` symbol do define padding of the number in sequence and where it's going to be used. + +
+
+ +![Create menu](assets/resolve_create_renaming_clips.png) + +
+
+ +
+
+ +Notice the relationship of following sections. Keys from **Shot Template Keywords** sections will be used for formating of templates in **Shot Hierarchy And Rename Settings** section. + +**Shot parent hierarchy** will be forming parents of the asset (shot) *the hidden root for this is project folder*. So for example of this template we will get resulging string `shots/sq01` + +**Clip name template** in context of clip sitting on track name `main` in second position `mainsq01sh020`. This is due track key is hosting `{_track_}` which is inheriting name form timeline track name. Other allowed namespases are: +- `{_sequence_}`: timeline name +- `{_clip_}`: clip name +- `{_trackIndex_}`: position of track on timeline from bottom +- `{_clipIndex_}`: clip positon on timeline from left + +
+
+ +![Create menu](assets/resolve_create_template_filling.png) + +
+
+ +### Vertical synchronization of subset attributes + +In case you are only working with two tracks on timeline where `main` track is going to be used as plates for compositors and `review` track holds mp4 clips for offlines and web preview. **Enable vertical sync** can be deactivated. + +In multiple tracks scenario - as mentioned [here](#rename-timeline-track-names) - it is recommended to activate **Enable vertical sync** and define the hero (driving) track to *main*. This will ensure that all of the clips on corresponding to the same shots will have the same publishing parameters. + +

+ +
+ +
+ +![Create menu](assets/resolve_create_single_track_rename_hero_track.png) + +
+ +
+ +![Create menu](assets/resolve_create_vertical_rename_creator_ui.png) + +
+
+ + +## Publishing Shots + +
+
+ +Once all `Chocolate` colored clips have gone through the [creator](#rcreate-menu), have been colored to `Pink` color and a marker has been created for each of them, it means they have been successfully converted to publishable clips. Now we can run **Publisher** - it's button can be found in the OpenPype menu. + +

+
+ +
+
+ +![Create menu](assets/resolve_publish_instance_review_main.png) +Notice that the main track clips and review had been merged into one instance. And since it is main `hero` clip it is also holding all new shot metadata. For that reason it also create secon instance for each with `shot` family. This instance will create all shot hierarchy and pass frame range attributes to shot (asset). + +
+
+ +
+
+ +![Create menu](assets/resolve_publish_instance_other_plateSubsets.png) +Also notice how the subset name is formed form a *track* name and *subset family* from previous steps. + +Also important is to notice the asset name in *OpenPypeData* at marker - the name is the same for all **Vertically renamed** shots as they have been grouped together. Unfortunately Resolve is not allowing to rename the clips so the only way to know is to see it in marker's metadata. + +
+
+ +
diff --git a/website/docs/assets/admin_hosts_aftereffects_settings.png b/website/docs/assets/admin_hosts_aftereffects_settings.png new file mode 100644 index 0000000000..9b879585f8 Binary files /dev/null and b/website/docs/assets/admin_hosts_aftereffects_settings.png differ diff --git a/website/docs/assets/resolve_clip_instances_pink_with_marker_in_middle.png b/website/docs/assets/resolve_clip_instances_pink_with_marker_in_middle.png new file mode 100644 index 0000000000..403f6e9433 Binary files /dev/null and b/website/docs/assets/resolve_clip_instances_pink_with_marker_in_middle.png differ diff --git a/website/docs/assets/resolve_create_audio_resolution.png b/website/docs/assets/resolve_create_audio_resolution.png new file mode 100644 index 0000000000..af22c7467e Binary files /dev/null and b/website/docs/assets/resolve_create_audio_resolution.png differ diff --git a/website/docs/assets/resolve_create_clips.png b/website/docs/assets/resolve_create_clips.png new file mode 100644 index 0000000000..b589bfb61e Binary files /dev/null and b/website/docs/assets/resolve_create_clips.png differ diff --git a/website/docs/assets/resolve_create_object_naming_convention.png b/website/docs/assets/resolve_create_object_naming_convention.png new file mode 100644 index 0000000000..13de366ef6 Binary files /dev/null and b/website/docs/assets/resolve_create_object_naming_convention.png differ diff --git a/website/docs/assets/resolve_create_renaming_clips.png b/website/docs/assets/resolve_create_renaming_clips.png new file mode 100644 index 0000000000..20c303e50a Binary files /dev/null and b/website/docs/assets/resolve_create_renaming_clips.png differ diff --git a/website/docs/assets/resolve_create_single_track_rename_hero_track.png b/website/docs/assets/resolve_create_single_track_rename_hero_track.png new file mode 100644 index 0000000000..5f68258d1d Binary files /dev/null and b/website/docs/assets/resolve_create_single_track_rename_hero_track.png differ diff --git a/website/docs/assets/resolve_create_subset_name_review_track.png b/website/docs/assets/resolve_create_subset_name_review_track.png new file mode 100644 index 0000000000..4efbff8409 Binary files /dev/null and b/website/docs/assets/resolve_create_subset_name_review_track.png differ diff --git a/website/docs/assets/resolve_create_template_filling.png b/website/docs/assets/resolve_create_template_filling.png new file mode 100644 index 0000000000..faa8c51ee3 Binary files /dev/null and b/website/docs/assets/resolve_create_template_filling.png differ diff --git a/website/docs/assets/resolve_create_vertical_rename_creator_ui.png b/website/docs/assets/resolve_create_vertical_rename_creator_ui.png new file mode 100644 index 0000000000..e163844993 Binary files /dev/null and b/website/docs/assets/resolve_create_vertical_rename_creator_ui.png differ diff --git a/website/docs/assets/resolve_create_vertical_rename_timeline.png b/website/docs/assets/resolve_create_vertical_rename_timeline.png new file mode 100644 index 0000000000..3e57db4119 Binary files /dev/null and b/website/docs/assets/resolve_create_vertical_rename_timeline.png differ diff --git a/website/docs/assets/resolve_creator_clip_marker_do_not_change.png b/website/docs/assets/resolve_creator_clip_marker_do_not_change.png new file mode 100644 index 0000000000..11cc5c4618 Binary files /dev/null and b/website/docs/assets/resolve_creator_clip_marker_do_not_change.png differ diff --git a/website/docs/assets/resolve_creator_framestart_handles.png b/website/docs/assets/resolve_creator_framestart_handles.png new file mode 100644 index 0000000000..65328fe041 Binary files /dev/null and b/website/docs/assets/resolve_creator_framestart_handles.png differ diff --git a/website/docs/assets/resolve_creator_subset_name.png b/website/docs/assets/resolve_creator_subset_name.png new file mode 100644 index 0000000000..4a42c5af2c Binary files /dev/null and b/website/docs/assets/resolve_creator_subset_name.png differ diff --git a/website/docs/assets/resolve_fusion_menu.png b/website/docs/assets/resolve_fusion_menu.png new file mode 100644 index 0000000000..ae1939690c Binary files /dev/null and b/website/docs/assets/resolve_fusion_menu.png differ diff --git a/website/docs/assets/resolve_fusion_script_settings.png b/website/docs/assets/resolve_fusion_script_settings.png new file mode 100644 index 0000000000..6d903b3ef4 Binary files /dev/null and b/website/docs/assets/resolve_fusion_script_settings.png differ diff --git a/website/docs/assets/resolve_fusion_tab.png b/website/docs/assets/resolve_fusion_tab.png new file mode 100644 index 0000000000..657d53cb16 Binary files /dev/null and b/website/docs/assets/resolve_fusion_tab.png differ diff --git a/website/docs/assets/resolve_menu_openpype.png b/website/docs/assets/resolve_menu_openpype.png new file mode 100644 index 0000000000..9812858072 Binary files /dev/null and b/website/docs/assets/resolve_menu_openpype.png differ diff --git a/website/docs/assets/resolve_menu_openpype_opened.png b/website/docs/assets/resolve_menu_openpype_opened.png new file mode 100644 index 0000000000..9b0e35569b Binary files /dev/null and b/website/docs/assets/resolve_menu_openpype_opened.png differ diff --git a/website/docs/assets/resolve_publish_instance_other_plateSubsets.png b/website/docs/assets/resolve_publish_instance_other_plateSubsets.png new file mode 100644 index 0000000000..fd5f857da5 Binary files /dev/null and b/website/docs/assets/resolve_publish_instance_other_plateSubsets.png differ diff --git a/website/docs/assets/resolve_publish_instance_review_main.png b/website/docs/assets/resolve_publish_instance_review_main.png new file mode 100644 index 0000000000..0cf5ed3b99 Binary files /dev/null and b/website/docs/assets/resolve_publish_instance_review_main.png differ diff --git a/website/docs/assets/resolve_remame_track_names.png b/website/docs/assets/resolve_remame_track_names.png new file mode 100644 index 0000000000..01174ea644 Binary files /dev/null and b/website/docs/assets/resolve_remame_track_names.png differ diff --git a/website/docs/assets/resolve_select_clips_timeline_chocolate.png b/website/docs/assets/resolve_select_clips_timeline_chocolate.png new file mode 100644 index 0000000000..b4a682e83a Binary files /dev/null and b/website/docs/assets/resolve_select_clips_timeline_chocolate.png differ diff --git a/website/docs/dev_build.md b/website/docs/dev_build.md index 9523035705..14efeaa850 100644 --- a/website/docs/dev_build.md +++ b/website/docs/dev_build.md @@ -1,6 +1,6 @@ --- id: dev_build -title: Build openPYPE from source +title: Build OpenPYPE from source sidebar_label: Build --- @@ -45,12 +45,12 @@ To start OpenPype from source you need to 2) Run `.\tools\run_tray.ps1` if you have all required dependencies on your machine you should be greeted with OpenPype igniter window and once you give it your Mongo URL, with OpenPype icon in the system tray. -### To build openPype: +### To build OpenPype: 1) Run `.\tools\create_env.ps1` to create virtual environment in `.\venv` 2) Run `.\tools\build.ps1` to build pype executables in `.\build\` -To create distributable openPype versions, run `./tools/create_zip.ps1` - that will +To create distributable OpenPype versions, run `./tools/create_zip.ps1` - that will create zip file with name `pype-vx.x.x.zip` parsed from current pype repository and copy it to user data dir. You can specify `--path /path/to/zip` to force it into a different location. This can be used to prepare new version releases for artists in the studio environment @@ -61,7 +61,24 @@ without the need to re-build the whole package -To build pype on linux you wil need: +#### Docker +You can use Docker to build OpenPype. Just run: +```sh +sudo ./tools/docker_build.sh +``` +and you should have built OpenPype in `build` directory. It is using **Centos 7** +as a base image. + +You can pull the image: + +```sh +# replace 3.0.0 tag with version you want +docker pull pypeclub/openpype:3.0.0 +``` +See https://hub.docker.com/r/pypeclub/openpype/tag for more. + +#### Manual build +To build OpenPype on Linux you wil need: - **[curl](https://curl.se)** on systems that doesn't have one preinstalled. - Python header files installed (**python3-dev** on Ubuntu for example). @@ -143,7 +160,7 @@ pyenv local 3.7.9 To build pype on MacOS you wil need: - **[Homebrew](https://brew.sh)**, Easy way of installing everything necessary is to use. -- **[CMake](https://cmake.org/)** to build some external openPype dependencies. +- **[CMake](https://cmake.org/)** to build some external OpenPype dependencies. - **XCode Command Line Tools** (or some other build system) 1) Install **Homebrew**: diff --git a/website/sidebars.js b/website/sidebars.js index 41611190fd..ad4ebc7dbf 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -22,6 +22,7 @@ module.exports = { "artist_hosts_blender", "artist_hosts_harmony", "artist_hosts_aftereffects", + "artist_hosts_resolve", "artist_hosts_photoshop", "artist_hosts_tvpaint", "artist_hosts_unreal", @@ -82,7 +83,9 @@ module.exports = { type: "category", label: "Integrations", items: [ - "admin_hosts_blender" + "admin_hosts_blender", + "admin_hosts_resolve", + "admin_hosts_aftereffects" ], }, {