Merge branch 'develop' of github.com:pypeclub/pype into feature/sync_server_settings_changes

This commit is contained in:
Petr Kalis 2021-05-17 10:03:21 +02:00
commit 0bb21ee727
75 changed files with 1663 additions and 430 deletions

146
.dockerignore Normal file
View file

@ -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/

82
Dockerfile Normal file
View file

@ -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

View file

@ -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

View file

@ -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"),

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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"
]

View file

@ -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.

View file

@ -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()

View file

@ -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"
)
)

View file

@ -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
}
}
}

View file

@ -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)

View file

@ -78,6 +78,10 @@
"type": "schema",
"name": "schema_project_hiero"
},
{
"type": "schema",
"name": "schema_project_aftereffects"
},
{
"type": "schema",
"name": "schema_project_harmony"

View file

@ -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"
}
]
}
]
}
]
}

View file

@ -23,7 +23,6 @@
"type": "dict-modifiable",
"key": "variants",
"collapsible_key": true,
"dynamic_label": false,
"use_label_wrap": false,
"object_type": {
"type": "dict",

View file

@ -23,7 +23,6 @@
"type": "dict-modifiable",
"key": "variants",
"collapsible_key": true,
"dynamic_label": false,
"use_label_wrap": false,
"object_type": {
"type": "dict",

View file

@ -23,7 +23,6 @@
"type": "dict-modifiable",
"key": "variants",
"collapsible_key": true,
"dynamic_label": false,
"use_label_wrap": false,
"object_type": {
"type": "dict",

View file

@ -23,7 +23,6 @@
"type": "dict-modifiable",
"key": "variants",
"collapsible_key": true,
"dynamic_label": false,
"use_label_wrap": false,
"object_type": {
"type": "dict",

View file

@ -19,7 +19,6 @@
"type": "dict-modifiable",
"key": "variants",
"collapsible_key": true,
"dynamic_label": false,
"use_label_wrap": false,
"object_type": {
"type": "dict",

View file

@ -23,7 +23,6 @@
"type": "dict-modifiable",
"key": "variants",
"collapsible_key": true,
"dynamic_label": false,
"use_label_wrap": false,
"object_type": {
"type": "dict",

View file

@ -23,7 +23,6 @@
"type": "dict-modifiable",
"key": "variants",
"collapsible_key": true,
"dynamic_label": false,
"use_label_wrap": false,
"object_type": {
"type": "dict",

View file

@ -24,7 +24,6 @@
"type": "dict-modifiable",
"key": "variants",
"collapsible_key": true,
"dynamic_label": false,
"use_label_wrap": false,
"object_type": {
"type": "dict",

View file

@ -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)

View file

@ -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:

View file

@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-
"""Package declaring Pype version."""
__version__ = "3.0.0-rc3"
__version__ = "3.0.0-rc4"

View file

@ -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 <info@openpype.io>"]
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:..."
hash = "sha256:..."

View file

@ -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")

View file

@ -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

View file

@ -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~ · ·· ·
· ' '· · ·· · · · ·· ·
"@

View file

@ -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

View file

@ -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')) {

View file

@ -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

View file

@ -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~ · ·· ·
· ' '· · ·· · · · ·· ·
"@

View file

@ -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
}

65
tools/docker_build.sh Executable file
View file

@ -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

View file

@ -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

View file

@ -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~ · ·· ·
· ' '· · ·· · · · ·· ·
"@

View file

@ -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
}

View file

@ -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~ · ·· ·
· ' '· · ·· · · · ·· ·
"@

View file

@ -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
}

View file

@ -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]}")))

View file

@ -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~ · ·· ·
· ' '· · ·· · · · ·· ·
"@

View file

@ -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

View file

@ -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]}")))

View file

@ -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~ · ·· ·
· ' '· · ·· · · · ·· ·
"@

View file

@ -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
}

View file

@ -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.

View file

@ -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.
<Tabs
groupId="platforms"
defaultValue="win"
values={[
{label: 'Windows', value: 'win'},
{label: 'Linux', value: 'linux'},
{label: 'Mac', value: 'mac'},
]}>
<TabItem value="win">
`%LOCALAPPDATA%\Programs\Python\Python36`
</TabItem>
<TabItem value="linux">
`/opt/Python/3.6/bin`
</TabItem>
<TabItem value="mac">
`~/Library/Python/3.6/bin`
</TabItem>
</Tabs>
### 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).
<Tabs
groupId="platforms"
defaultValue="win"
values={[
{label: 'Windows', value: 'win'},
{label: 'Linux', value: 'linux'},
{label: 'Mac', value: 'mac'},
]}>
<TabItem value="win">
paste to any terminal of your choice
```bash
%LOCALAPPDATA%\Programs\Python\Python36\python.exe -m pip install PySide2
```
</TabItem>
<TabItem value="linux">
paste to any terminal of your choice
```bash
/opt/Python/3.6/bin/python -m pip install PySide2
```
</TabItem>
<TabItem value="mac">
paste to any terminal of your choice
```bash
~/Library/Python/3.6/bin/python -m pip install PySide2
```
</TabItem>
</Tabs>
<div class="row markdown">
### Set Resolve's Fusion settings for Python 3.6 interpereter
<div class="col col--6 markdown">
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
</div>
<div class="col col--6 markdown">
![Create menu](assets/resolve_fusion_tab.png)
![Create menu](assets/resolve_fusion_menu.png)
![Create menu](assets/resolve_fusion_script_settings.png)
</div>
</div>

View file

@ -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)
<div class="row markdown">
## 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.
</div>
<div class="row markdown">
### 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.
<div class="col col--6 markdown">
![Create menu](assets/resolve_select_clips_timeline_chocolate.png)
</div>
</div>
### Rename timeline track names
<div class="row markdown">
<div class="col col --6 markdown">
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**
<br></br>
</div>
<div class="col col--6 markdown">
![Create menu](assets/resolve_creator_subset_name.png)
The name of the resulting *subset* can be seen in the **OpenPypeData** marker.
<br></br><br></br>
</div>
<div class="col col--6 markdown">
![Create menu](assets/resolve_remame_track_names.png)
Simple track setup where we are only using `main` and `review` track names.
</div>
<div class="col col--6 markdown">
![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).
</div>
</div>
### Create menu...
<div class="row markdown">
<div class="col col--6 markdown">
After all clips which are intended to be converted to publishable instances are colored to `Chocolate` color, you can open OpenPype menu.
</div>
<div class="col col--6 markdown">
![Create menu](assets/resolve_menu_openpype.png)
</div>
</div>
<div class="row markdown">
<div class="col col--6 markdown">
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.
</div>
<div class="col col--6 markdown">
![Create menu](assets/resolve_create_clips.png)
</div>
</div>
<div class="row markdown">
<div class="col col--6 markdown">
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.
</div>
<div class="col col--6 markdown">
![Create menu](assets/resolve_create_renaming_clips.png)
</div>
</div>
<div class="row markdown">
<div class="col col--6 markdown">
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
</div>
<div class="col col--6 markdown">
![Create menu](assets/resolve_create_template_filling.png)
</div>
</div>
### 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.
<br></br>
<div class="row markdown">
<div class="col col--6 markdown">
![Create menu](assets/resolve_create_single_track_rename_hero_track.png)
</div>
<div class="col col--6 markdown">
![Create menu](assets/resolve_create_vertical_rename_creator_ui.png)
</div>
</div>
## Publishing Shots
<div class="row markdown">
<div class="col--6 markdown">
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.
<br></br>
</div>
<div class="row markdown">
<div class="col --6 markdown">
![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).
</div>
</div>
<div class="row markdown">
<div class="col --6 markdown">
![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.
</div>
</div>
</div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

View file

@ -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
</TabItem>
<TabItem value="linux">
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**:

View file

@ -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"
],
},
{