Merge pull request #1744 from pypeclub/feature/move-to-pyside2

This commit is contained in:
Milan Kolar 2021-10-18 15:26:14 +02:00 committed by GitHub
commit 7c2da65a69
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 468 additions and 216 deletions

View file

@ -87,7 +87,7 @@ 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
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
@ -142,5 +142,6 @@ cython_debug/
.poetry/
.github/
vendor/bin/
vendor/python/
docs/
website/

1
.gitignore vendored
View file

@ -39,6 +39,7 @@ Temporary Items
/dist/
/vendor/bin/*
/vendor/python/*
/.venv
/venv/

View file

@ -1,7 +1,9 @@
# Build Pype docker image
FROM centos:7 AS builder
ARG OPENPYPE_PYTHON_VERSION=3.7.10
FROM debian:bookworm-slim AS builder
ARG OPENPYPE_PYTHON_VERSION=3.7.12
LABEL maintainer="info@openpype.io"
LABEL description="Docker Image to build and run OpenPype"
LABEL org.opencontainers.image.name="pypeclub/openpype"
LABEL org.opencontainers.image.title="OpenPype Docker Image"
LABEL org.opencontainers.image.url="https://openpype.io/"
@ -9,56 +11,49 @@ 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
ARG DEBIAN_FRONTEND=noninteractive
# 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 \
# update base
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
bash \
which \
git \
devtoolset-7-gcc* \
make \
cmake \
make \
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
build-essential \
checkinstall \
libssl-dev \
zlib1g-dev \
libbz2-dev \
libreadline-dev \
libsqlite3-dev \
llvm \
libncursesw5-dev \
xz-utils \
tk-dev \
libxml2-dev \
libxmlsec1-dev \
libffi-dev \
liblzma-dev \
patchelf
SHELL ["/bin/bash", "-c"]
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 \
RUN curl https://pyenv.run | bash \
&& 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}
&& echo 'eval "$(pyenv init --path)"' >> $HOME/.bashrc \
&& 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
RUN chmod +x /opt/openpype/tools/create_env.sh && chmod +x /opt/openpype/tools/build.sh
WORKDIR /opt/openpype
@ -67,16 +62,8 @@ RUN cd /opt/openpype \
&& pyenv local ${OPENPYPE_PYTHON_VERSION}
RUN source $HOME/.bashrc \
&& ./tools/create_env.sh
RUN source $HOME/.bashrc \
&& ./tools/create_env.sh \
&& ./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
&& bash ./tools/build.sh

98
Dockerfile.centos7 Normal file
View file

@ -0,0 +1,98 @@
# 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 \
make \
devtoolset-7 \
cmake \
curl \
wget \
gcc \
zlib-devel \
bzip2 \
bzip2-devel \
readline-devel \
sqlite sqlite-devel \
openssl-devel \
openssl-libs \
tk-devel libffi-devel \
patchelf \
automake \
autoconf \
ncurses \
ncurses-devel \
qt5-qtbase-devel \
&& yum clean all
# we need to build our own patchelf
WORKDIR /temp-patchelf
RUN git clone https://github.com/NixOS/patchelf.git . \
&& source scl_source enable devtoolset-7 \
&& ./bootstrap.sh \
&& ./configure \
&& make \
&& make install
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
RUN 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 \
&& cp /root/.pyenv/versions/${OPENPYPE_PYTHON_VERSION}/lib/libpython* ./build/exe.linux-x86_64-3.7/lib
RUN cd /opt/openpype \
rm -rf ./vendor/bin

View file

@ -133,6 +133,12 @@ Easiest way to build OpenPype on Linux is using [Docker](https://www.docker.com/
sudo ./tools/docker_build.sh
```
This will by default use Debian as base image. If you need to make Centos 7 compatible build, please run:
```sh
sudo ./tools/docker_build.sh centos7
```
If all is successful, you'll find built OpenPype in `./build/` folder.
#### Manual build
@ -158,6 +164,11 @@ you'll need also additional libraries for Qt5:
```sh
sudo apt install qt5-default
```
or if you are on Ubuntu > 20.04, there is no `qt5-default` packages so you need to install its content individually:
```sh
sudo apt-get install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools
```
</details>
<details>

View file

@ -48,7 +48,7 @@ class _ModuleClass(object):
def __getattr__(self, attr_name):
if attr_name not in self.__attributes__:
if attr_name in ("__path__"):
if attr_name in ("__path__", "__file__"):
return None
raise ImportError("No module named {}.{}".format(
self.name, attr_name
@ -104,6 +104,9 @@ class _InterfacesClass(_ModuleClass):
"""
def __getattr__(self, attr_name):
if attr_name not in self.__attributes__:
if attr_name in ("__path__", "__file__"):
return None
# Fake Interface if is not missing
self.__attributes__[attr_name] = type(
attr_name,

View file

@ -371,7 +371,7 @@ class FtrackModule(
return self.tray_module.validate()
def tray_exit(self):
return self.tray_module.stop_action_server()
self.tray_module.tray_exit()
def set_credentials_to_env(self, username, api_key):
os.environ["FTRACK_API_USER"] = username or ""

View file

@ -289,6 +289,10 @@ class FtrackTrayWrapper:
parent_menu.addMenu(tray_menu)
def tray_exit(self):
self.stop_action_server()
self.stop_timer_thread()
# Definition of visibility of each menu actions
def set_menu_visibility(self):
self.tray_server_menu.menuAction().setVisible(self.bool_logged)

View file

@ -150,6 +150,7 @@ class TimersManager(OpenPypeModule, ITrayService):
def tray_exit(self):
if self._idle_manager:
self._idle_manager.stop()
self._idle_manager.wait()
def start_timer(self, project_name, asset_name, task_name, hierarchy):
"""

View file

@ -214,7 +214,8 @@ class BaseWidget(QtWidgets.QWidget):
def _paste_value_actions(self, menu):
output = []
# Allow paste of value only if were copied from this UI
mime_data = QtWidgets.QApplication.clipboard().mimeData()
clipboard = QtWidgets.QApplication.clipboard()
mime_data = clipboard.mimeData()
mime_value = mime_data.data("application/copy_settings_value")
# Skip if there is nothing to do
if not mime_value:

View file

@ -508,7 +508,7 @@ class SettingsCategoryWidget(QtWidgets.QWidget):
first_invalid_item = invalid_items[0]
self.scroll_widget.ensureWidgetVisible(first_invalid_item)
if first_invalid_item.isVisible():
first_invalid_item.setFocus(True)
first_invalid_item.setFocus()
return False
def on_saved(self, saved_tab_widget):

View file

@ -128,9 +128,9 @@ class ModifiableDictEmptyItem(QtWidgets.QWidget):
def add_new_item(self, key=None, label=None):
input_field = self.entity_widget.add_new_key(key, label)
if self.collapsible_key:
self.key_input.setFocus(True)
self.key_input.setFocus()
else:
input_field.key_input.setFocus(True)
input_field.key_input.setFocus()
return input_field
def _on_add_clicked(self):
@ -563,7 +563,7 @@ class ModifiableDictItem(QtWidgets.QWidget):
def on_add_clicked(self):
widget = self.entity_widget.add_new_key(None, None)
widget.key_input.setFocus(True)
widget.key_input.setFocus()
def on_edit_pressed(self):
if not self.key_input.isVisible():

View file

@ -357,7 +357,7 @@ class ListWidget(InputWidget):
new_entity = self.entity.add_new_item(row)
input_field = self._input_fields_by_entity_id.get(new_entity.id)
if input_field is not None:
input_field.input_field.setFocus(True)
input_field.input_field.setFocus()
return new_entity
def add_row(self, child_entity, row=None):

View file

@ -268,7 +268,6 @@ class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
# Set modules
self.tray_man = TrayManager(self, self.parent)
self.tray_man.initialize_modules()
# Add menu to Context of SystemTrayIcon
self.setContextMenu(self.menu)
@ -291,6 +290,17 @@ class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
self._doubleclick = False
self._click_pos = None
self._initializing_modules = False
@property
def initializing_modules(self):
return self._initializing_modules
def initialize_modules(self):
self._initializing_modules = True
self.tray_man.initialize_modules()
self._initializing_modules = False
def _click_timer_timeout(self):
self._click_timer.stop()
doubleclick = self._doubleclick
@ -334,38 +344,48 @@ class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
QtCore.QCoreApplication.exit()
class TrayMainWindow(QtWidgets.QMainWindow):
""" TrayMainWindow is base of Pype application.
Every widget should have set this window as parent because
QSystemTrayIcon widget is not allowed to be a parent of any widget.
"""
class PypeTrayStarter(QtCore.QObject):
def __init__(self, app):
super(TrayMainWindow, self).__init__()
self.app = app
app.setQuitOnLastWindowClosed(False)
self._app = app
self._splash = None
self.tray_widget = SystemTrayIcon(self)
self.tray_widget.show()
main_window = QtWidgets.QMainWindow()
tray_widget = SystemTrayIcon(main_window)
start_timer = QtCore.QTimer()
start_timer.setInterval(100)
start_timer.start()
class PypeTrayApplication(QtWidgets.QApplication):
"""Qt application manages application's control flow."""
start_timer.timeout.connect(self._on_start_timer)
def __init__(self):
super(PypeTrayApplication, self).__init__(sys.argv)
# Allows to close widgets without exiting app
self.setQuitOnLastWindowClosed(False)
self._main_window = main_window
self._tray_widget = tray_widget
self._timer_counter = 0
self._start_timer = start_timer
# Sets up splash
splash_widget = self.set_splash()
def _on_start_timer(self):
if self._timer_counter == 0:
self._timer_counter += 1
splash = self._get_splash()
splash.show()
self._tray_widget.show()
splash_widget.show()
self.processEvents()
self.main_window = TrayMainWindow(self)
splash_widget.hide()
elif self._timer_counter == 1:
self._timer_counter += 1
self._tray_widget.initialize_modules()
def set_splash(self):
elif not self._tray_widget.initializing_modules:
splash = self._get_splash()
splash.hide()
self._start_timer.stop()
def _get_splash(self):
if self._splash is None:
self._splash = self._create_splash()
return self._splash
def _create_splash(self):
splash_pix = QtGui.QPixmap(resources.get_openpype_splash_filepath())
splash = QtWidgets.QSplashScreen(splash_pix)
splash.setMask(splash_pix.mask())
@ -377,7 +397,12 @@ class PypeTrayApplication(QtWidgets.QApplication):
def main():
app = PypeTrayApplication()
app = QtWidgets.QApplication.instance()
if not app:
app = QtWidgets.QApplication([])
starter = PypeTrayStarter(app)
# TODO remove when pype.exe will have an icon
if os.name == "nt":
import ctypes

83
poetry.lock generated
View file

@ -288,15 +288,20 @@ test = ["pytest (>=6.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pret
[[package]]
name = "cx-freeze"
version = "6.6"
version = "6.7"
description = "Create standalone executables from Python scripts"
category = "dev"
optional = false
python-versions = ">=3.6"
[package.dependencies]
cx-Logging = {version = ">=3.0", markers = "sys_platform == \"win32\""}
importlib-metadata = ">=3.1.1"
cx-logging = {version = ">=3.0", markers = "sys_platform == \"win32\""}
importlib-metadata = ">=4.3.1"
[package.source]
type = "legacy"
url = "https://distribute.openpype.io/wheels"
reference = "openpype"
[[package]]
name = "cx-logging"
@ -1013,34 +1018,6 @@ category = "main"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]]
name = "pyqt5"
version = "5.15.4"
description = "Python bindings for the Qt cross platform application toolkit"
category = "main"
optional = false
python-versions = ">=3.6"
[package.dependencies]
PyQt5-Qt5 = ">=5.15"
PyQt5-sip = ">=12.8,<13"
[[package]]
name = "pyqt5-qt5"
version = "5.15.2"
description = "The subset of a Qt installation needed by PyQt5."
category = "main"
optional = false
python-versions = "*"
[[package]]
name = "pyqt5-sip"
version = "12.9.0"
description = "The sip module support for PyQt5"
category = "main"
optional = false
python-versions = ">=3.5"
[[package]]
name = "pyrsistent"
version = "0.17.3"
@ -1814,17 +1791,7 @@ cryptography = [
{file = "cryptography-3.4.7-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:bf40af59ca2465b24e54f671b2de2c59257ddc4f7e5706dbd6930e26823668d3"},
{file = "cryptography-3.4.7.tar.gz", hash = "sha256:3d10de8116d25649631977cb37da6cbdd2d6fa0e0281d014a5b7d337255ca713"},
]
cx-freeze = [
{file = "cx_Freeze-6.6-cp36-cp36m-win32.whl", hash = "sha256:b3d3a6bcd1a07c50b4e1c907f14842642156110e63a99cd5c73b8a24751e9b97"},
{file = "cx_Freeze-6.6-cp36-cp36m-win_amd64.whl", hash = "sha256:1935266ec644ea4f7e584985f44cefc0622a449a09980d990833a1a2afcadac8"},
{file = "cx_Freeze-6.6-cp37-cp37m-win32.whl", hash = "sha256:1eac2b0f254319cc641ce25bd83337effd7936092562fde701f3ffb40e0274ec"},
{file = "cx_Freeze-6.6-cp37-cp37m-win_amd64.whl", hash = "sha256:2bc46ef6d510811b6002f34a3ae4cbfdea44e18644febd2a404d3ee8e48a9fc4"},
{file = "cx_Freeze-6.6-cp38-cp38-win32.whl", hash = "sha256:46eb50ebc46f7ae236d16c6a52671ab0f7bb479bea668da19f4b6de3cc413e9e"},
{file = "cx_Freeze-6.6-cp38-cp38-win_amd64.whl", hash = "sha256:8c3b00476ce385bb58595bffce55aed031e5a6e16ab6e14d8bee9d1d569e46c3"},
{file = "cx_Freeze-6.6-cp39-cp39-win32.whl", hash = "sha256:6e9340cbcf52d4836980ecc83ddba4f7704ff6654dd41168c146b74f512977ce"},
{file = "cx_Freeze-6.6-cp39-cp39-win_amd64.whl", hash = "sha256:2fcf1c8b77ae5c06f45be3a9aff79e1dd808c0d624e97561f840dec5ea9b214a"},
{file = "cx_Freeze-6.6.tar.gz", hash = "sha256:c4af8ad3f7e7d71e291c1dec5d0fb26bbe92df834b098ed35434c901fbd6762f"},
]
cx-freeze = []
cx-logging = [
{file = "cx_Logging-3.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:9fcd297e5c51470521c47eff0f86ba844aeca6be97e13c3e2114ebdf03fa3c96"},
{file = "cx_Logging-3.0-cp36-cp36m-win32.whl", hash = "sha256:0df4be47c5022cc54316949e283403214568ef599817ced0c0972183d6d4fabb"},
@ -2355,38 +2322,6 @@ pyparsing = [
{file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
{file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
]
pyqt5 = [
{file = "PyQt5-5.15.4-cp36.cp37.cp38.cp39-abi3-macosx_10_13_intel.whl", hash = "sha256:8c0848ba790a895801d5bfd171da31cad3e551dbcc4e59677a3b622de2ceca98"},
{file = "PyQt5-5.15.4-cp36.cp37.cp38.cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:883a549382fc22d29a0568f3ef20b38c8e7ab633a59498ac4eb63a3bf36d3fd3"},
{file = "PyQt5-5.15.4-cp36.cp37.cp38.cp39-none-win32.whl", hash = "sha256:a88526a271e846e44779bb9ad7a738c6d3c4a9d01e15a128ecfc6dd4696393b7"},
{file = "PyQt5-5.15.4-cp36.cp37.cp38.cp39-none-win_amd64.whl", hash = "sha256:213bebd51821ed89b4d5b35bb10dbe67564228b3568f463a351a08e8b1677025"},
{file = "PyQt5-5.15.4.tar.gz", hash = "sha256:2a69597e0dd11caabe75fae133feca66387819fc9bc050f547e5551bce97e5be"},
]
pyqt5-qt5 = [
{file = "PyQt5_Qt5-5.15.2-py3-none-macosx_10_13_intel.whl", hash = "sha256:76980cd3d7ae87e3c7a33bfebfaee84448fd650bad6840471d6cae199b56e154"},
{file = "PyQt5_Qt5-5.15.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:1988f364ec8caf87a6ee5d5a3a5210d57539988bf8e84714c7d60972692e2f4a"},
{file = "PyQt5_Qt5-5.15.2-py3-none-win32.whl", hash = "sha256:9cc7a768b1921f4b982ebc00a318ccb38578e44e45316c7a4a850e953e1dd327"},
{file = "PyQt5_Qt5-5.15.2-py3-none-win_amd64.whl", hash = "sha256:750b78e4dba6bdf1607febedc08738e318ea09e9b10aea9ff0d73073f11f6962"},
]
pyqt5-sip = [
{file = "PyQt5_sip-12.9.0-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:d85002238b5180bce4b245c13d6face848faa1a7a9e5c6e292025004f2fd619a"},
{file = "PyQt5_sip-12.9.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:83c3220b1ca36eb8623ba2eb3766637b19eb0ce9f42336ad8253656d32750c0a"},
{file = "PyQt5_sip-12.9.0-cp36-cp36m-win32.whl", hash = "sha256:d8b2bdff7bbf45bc975c113a03b14fd669dc0c73e1327f02706666a7dd51a197"},
{file = "PyQt5_sip-12.9.0-cp36-cp36m-win_amd64.whl", hash = "sha256:69a3ad4259172e2b1aa9060de211efac39ddd734a517b1924d9c6c0cc4f55f96"},
{file = "PyQt5_sip-12.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:42274a501ab4806d2c31659170db14c282b8313d2255458064666d9e70d96206"},
{file = "PyQt5_sip-12.9.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:6a8701892a01a5a2a4720872361197cc80fdd5f49c8482d488ddf38c9c84f055"},
{file = "PyQt5_sip-12.9.0-cp37-cp37m-win32.whl", hash = "sha256:ac57d796c78117eb39edd1d1d1aea90354651efac9d3590aac67fa4983f99f1f"},
{file = "PyQt5_sip-12.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4347bd81d30c8e3181e553b3734f91658cfbdd8f1a19f254777f906870974e6d"},
{file = "PyQt5_sip-12.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c446971c360a0a1030282a69375a08c78e8a61d568bfd6dab3dcc5cf8817f644"},
{file = "PyQt5_sip-12.9.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:fc43f2d7c438517ee33e929e8ae77132749c15909afab6aeece5fcf4147ffdb5"},
{file = "PyQt5_sip-12.9.0-cp38-cp38-win32.whl", hash = "sha256:055581c6fed44ba4302b70eeb82e979ff70400037358908f251cd85cbb3dbd93"},
{file = "PyQt5_sip-12.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:c5216403d4d8d857ec4a61f631d3945e44fa248aa2415e9ee9369ab7c8a4d0c7"},
{file = "PyQt5_sip-12.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a25b9843c7da6a1608f310879c38e6434331aab1dc2fe6cb65c14f1ecf33780e"},
{file = "PyQt5_sip-12.9.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:dd05c768c2b55ffe56a9d49ce6cc77cdf3d53dbfad935258a9e347cbfd9a5850"},
{file = "PyQt5_sip-12.9.0-cp39-cp39-win32.whl", hash = "sha256:4f8e05fe01d54275877c59018d8e82dcdd0bc5696053a8b830eecea3ce806121"},
{file = "PyQt5_sip-12.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:b09f4cd36a4831229fb77c424d89635fa937d97765ec90685e2f257e56a2685a"},
{file = "PyQt5_sip-12.9.0.tar.gz", hash = "sha256:d3e4489d7c2b0ece9d203ae66e573939f7f60d4d29e089c9f11daa17cfeaae32"},
]
pyrsistent = [
{file = "pyrsistent-0.17.3.tar.gz", hash = "sha256:2e636185d9eb976a18a8a8e96efce62f2905fea90041958d8cc2a189756ebf3e"},
]

View file

@ -49,7 +49,6 @@ Pillow = "^8.1" # only used for slates prototype
pyblish-base = "^1.8.8"
pynput = "^1.7.2" # idle manager in tray
pymongo = "^3.11.2"
pyqt5 = "^5.12.2" # ideally should be replaced with PySide2
"Qt.py" = "^1.3.3"
speedcopy = "^2.1"
six = "^1.15"
@ -63,14 +62,16 @@ jinxed = [
python3-xlib = { version="*", markers = "sys_platform == 'linux'"}
enlighten = "^1.9.0"
slack-sdk = "^3.6.0"
requests = "2.25.1"
pysftp = "^0.2.9"
dropbox = "^11.20.0"
[tool.poetry.dev-dependencies]
flake8 = "^3.7"
autopep8 = "^1.4"
coverage = "*"
cx_freeze = "^6.6"
cx_freeze = { version = "6.7", source = "openpype" }
GitPython = "^3.1.17"
jedi = "^0.13"
Jinja2 = "^2.11"
@ -89,7 +90,6 @@ wheel = "*"
enlighten = "*" # cool terminal progress bars
toml = "^0.10.2" # for parsing pyproject.toml
[tool.poetry.urls]
"Bug Tracker" = "https://github.com/pypeclub/openpype/issues"
"Discussions" = "https://github.com/pypeclub/openpype/discussions"
@ -104,6 +104,12 @@ build-backend = "poetry.core.masonry.api"
[openpype]
[openpype.pyside2]
# note: in here we can use pip version specifiers as this is installed with pip until
# Poetry will support custom location (-t flag for pip)
# https://pip.pypa.io/en/stable/cli/pip_install/#requirement-specifiers
version = "==5.15.2"
[openpype.thirdparty.ffmpeg.windows]
url = "https://distribute.openpype.io/thirdparty/ffmpeg-4.4-windows.zip"
hash = "dd51ba29d64ee238e7c4c3c7301b19754c3f0ee2e2a729c20a0e2789e72db925"

View file

@ -59,13 +59,14 @@ includes = []
excludes = [
"openpype"
]
bin_includes = []
bin_includes = [
"vendor"
]
include_files = [
"igniter",
"openpype",
"repos",
"schema",
"vendor",
"LICENSE",
"README.md"
]

View file

@ -124,6 +124,10 @@ else:
paths.append(frozen_libs)
os.environ["PYTHONPATH"] = os.pathsep.join(paths)
# Vendored python modules that must not be in PYTHONPATH environment but
# are required for OpenPype processes
vendor_python_path = os.path.join(OPENPYPE_ROOT, "vendor", "python")
sys.path.insert(0, vendor_python_path)
import blessed # noqa: E402
import certifi # noqa: E402

View file

@ -58,7 +58,7 @@ BICyan='\033[1;96m' # Cyan
BIWhite='\033[1;97m' # White
args=$@
disable_submodule_update = 0
disable_submodule_update=0
while :; do
case $1 in
--no-submodule-update)
@ -90,6 +90,7 @@ done
###############################################################################
detect_python () {
echo -e "${BIGreen}>>>${RST} Using python \c"
command -v python >/dev/null 2>&1 || { echo -e "${BIRed}- NOT FOUND${RST} ${BIYellow}You need Python 3.7 installed to continue.${RST}"; return 1; }
local version_command
version_command="import sys;print('{0}.{1}'.format(sys.version_info[0], sys.version_info[1]))"
local python_version
@ -122,7 +123,7 @@ clean_pyc () {
local path
path=$openpype_root
echo -e "${BIGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c"
find "$path" -path ./build -prune -o -regex '^.*\(__pycache__\|\.py[co]\)$' -delete
find "$path" -path ./build -o -regex '^.*\(__pycache__\|\.py[co]\)$' -delete
echo -e "${BIGreen}DONE${RST}"
}
@ -173,7 +174,7 @@ main () {
else
echo -e "${BIYellow}NOT FOUND${RST}"
echo -e "${BIYellow}***${RST} We need to install Poetry and virtual env ..."
. "$openpype_root/tools/create_env.sh" || { echo -e "${BIRed}!!!${RST} Poetry installation failed"; return; }
. "$openpype_root/tools/create_env.sh" || { echo -e "${BIRed}!!!${RST} Poetry installation failed"; return 1; }
fi
if [ "$disable_submodule_update" == 1 ]; then
@ -184,9 +185,9 @@ if [ "$disable_submodule_update" == 1 ]; then
fi
echo -e "${BIGreen}>>>${RST} Building ..."
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
"$POETRY_HOME/bin/poetry" run python "$openpype_root/setup.py" build > "$openpype_root/build/build.log" || { echo -e "${BIRed}!!!${RST} Build failed, see the build log."; return; }
"$POETRY_HOME/bin/poetry" run python "$openpype_root/setup.py" build &> "$openpype_root/build/build.log" || { echo -e "${BIRed}!!!${RST} Build failed, see the build log."; return 1; }
elif [[ "$OSTYPE" == "darwin"* ]]; then
"$POETRY_HOME/bin/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; }
"$POETRY_HOME/bin/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 1; }
fi
"$POETRY_HOME/bin/poetry" run python "$openpype_root/tools/build_dependencies.py"
@ -210,4 +211,6 @@ if [ "$disable_submodule_update" == 1 ]; then
echo -e "${BIWhite}$openpype_root/build${RST} directory."
}
main
return_code=0
main || return_code=$?
exit $return_code

View file

@ -23,6 +23,7 @@ import sys
import site
from distutils.util import get_platform
import platform
import subprocess
from pathlib import Path
import shutil
import blessed
@ -93,18 +94,18 @@ _print("Getting venv site-packages ...")
assert site_pkg, "No venv site-packages are found."
_print(f"Working with: {site_pkg}", 2)
build_dir = "exe.{}-{}".format(get_platform(), sys.version[0:3])
openpype_root = Path(os.path.dirname(__file__)).parent
# create full path
if platform.system().lower() == "darwin":
build_dir = Path(os.path.dirname(__file__)).parent.joinpath(
build_dir = openpype_root.joinpath(
"build",
"OpenPype.app",
"Contents",
"MacOS")
else:
build_dir = Path(os.path.dirname(__file__)).parent / "build" / build_dir
build_subdir = "exe.{}-{}".format(get_platform(), sys.version[0:3])
build_dir = openpype_root / "build" / build_subdir
_print(f"Using build at {build_dir}", 2)
if not build_dir.exists():
@ -112,7 +113,28 @@ if not build_dir.exists():
_print("Probably freezing of code failed. Check ./build/build.log", 3)
sys.exit(1)
def _progress(_base, _names):
progress_bar.update()
return []
deps_dir = build_dir / "dependencies"
vendor_dir = build_dir / "vendor"
vendor_src = openpype_root / "vendor"
# copy vendor files
_print("Copying vendor files ...")
total_files = count_folders(vendor_src)
progress_bar = enlighten.Counter(
total=total_files, desc="Copying vendor files ...",
units="%", color=(64, 128, 222))
shutil.copytree(vendor_src.as_posix(),
vendor_dir.as_posix(),
ignore=_progress)
progress_bar.close()
# copy all files
_print("Copying dependencies ...")
@ -122,12 +144,6 @@ progress_bar = enlighten.Counter(
total=total_files, desc="Processing Dependencies",
units="%", color=(53, 178, 202))
def _progress(_base, _names):
progress_bar.update()
return []
shutil.copytree(site_pkg.as_posix(),
deps_dir.as_posix(),
ignore=_progress)
@ -135,15 +151,29 @@ progress_bar.close()
# iterate over frozen libs and create list to delete
libs_dir = build_dir / "lib"
# On Windows "python3.dll" is needed for PyQt5 from the build.
if platform.system().lower() == "windows":
src = Path(libs_dir / "PyQt5" / "python3.dll")
dst = Path(deps_dir / "PyQt5" / "python3.dll")
if src.exists():
shutil.copyfile(src, dst)
else:
_print("Could not find {}".format(src), 1)
sys.exit(1)
# On Linux use rpath from source libraries in destination libraries
if platform.system().lower() == "linux":
src_pyside_dir = openpype_root / "vendor" / "python" / "PySide2"
dst_pyside_dir = build_dir / "vendor" / "python" / "PySide2"
src_rpath_per_so_file = {}
for filepath in src_pyside_dir.glob("*.so"):
filename = filepath.name
rpath = (
subprocess.check_output(["patchelf", "--print-rpath", filepath])
.decode("utf-8")
.strip()
)
src_rpath_per_so_file[filename] = rpath
for filepath in dst_pyside_dir.glob("*.so"):
filename = filepath.name
if filename not in src_rpath_per_so_file:
continue
src_rpath = src_rpath_per_so_file[filename]
subprocess.check_call(
["patchelf", "--set-rpath", src_rpath, filepath]
)
to_delete = []
# _print("Finding duplicates ...")

View file

@ -88,6 +88,7 @@ done
###############################################################################
detect_python () {
echo -e "${BIGreen}>>>${RST} Using python \c"
command -v python >/dev/null 2>&1 || { echo -e "${BIRed}- NOT FOUND${RST} ${BIYellow}You need Python 3.7 installed to continue.${RST}"; return 1; }
local version_command="import sys;print('{0}.{1}'.format(sys.version_info[0], sys.version_info[1]))"
local python_version="$(python <<< ${version_command})"
oIFS="$IFS"
@ -125,7 +126,7 @@ clean_pyc () {
local path
path=$openpype_root
echo -e "${BIGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c"
find "$path" -path ./build -prune -o -regex '^.*\(__pycache__\|\.py[co]\)$' -delete
find "$path" -path ./build -o -regex '^.*\(__pycache__\|\.py[co]\)$' -delete
echo -e "${BIGreen}DONE${RST}"
}
@ -166,7 +167,7 @@ main () {
echo -e "${BIGreen}OK${RST}"
else
echo -e "${BIYellow}NOT FOUND${RST}"
install_poetry || { echo -e "${BIRed}!!!${RST} Poetry installation failed"; return; }
install_poetry || { echo -e "${BIRed}!!!${RST} Poetry installation failed"; return 1; }
fi
if [ -f "$openpype_root/poetry.lock" ]; then
@ -175,7 +176,11 @@ main () {
echo -e "${BIGreen}>>>${RST} Installing dependencies ..."
fi
"$POETRY_HOME/bin/poetry" install --no-root $poetry_verbosity || { echo -e "${BIRed}!!!${RST} Poetry environment installation failed"; return; }
"$POETRY_HOME/bin/poetry" install --no-root $poetry_verbosity || { echo -e "${BIRed}!!!${RST} Poetry environment installation failed"; return 1; }
if [ $? -ne 0 ] ; then
echo -e "${BIRed}!!!${RST} Virtual environment creation failed."
return 1
fi
echo -e "${BIGreen}>>>${RST} Cleaning cache files ..."
clean_pyc
@ -183,11 +188,15 @@ main () {
# reinstall these because of bug in poetry? or cx_freeze?
# cx_freeze will crash on missing __pychache__ on these but
# reinstalling them solves the problem.
echo -e "${BIGreen}>>>${RST} Fixing pycache bug ..."
"$POETRY_HOME/bin/poetry" run python -m pip install --force-reinstall pip
"$POETRY_HOME/bin/poetry" run pip install --force-reinstall setuptools
"$POETRY_HOME/bin/poetry" run pip install --force-reinstall wheel
"$POETRY_HOME/bin/poetry" run python -m pip install --force-reinstall pip
echo -e "${BIGreen}>>>${RST} Post-venv creation fixes ..."
local openpype_index=$("$POETRY_HOME/bin/poetry" run python "$openpype_root/tools/parse_pyproject.py" tool.poetry.source.0.url)
echo -e "${BIGreen}- ${RST} Using index: ${BIWhite}$openpype_index${RST}"
"$POETRY_HOME/bin/poetry" run pip install setuptools==49.6.0
"$POETRY_HOME/bin/poetry" run pip install --disable-pip-version-check --force-reinstall wheel
"$POETRY_HOME/bin/poetry" run python -m pip install --disable-pip-version-check --force-reinstall pip
"$POETRY_HOME/bin/poetry" run pip install --disable-pip-version-check --force-reinstall cx_freeze -i $openpype_index --extra-index-url https://pypi.org/simple
}
main -3
return_code=0
main || return_code=$?
exit $return_code

View file

@ -20,6 +20,41 @@ realpath () {
echo $(cd $(dirname "$1"); pwd)/$(basename "$1")
}
create_container () {
if [ ! -f "$openpype_root/build/docker-image.id" ]; then
echo -e "${BIRed}!!!${RST} Docker command failed, cannot find image id."
exit 1
fi
local id=$(<"$openpype_root/build/docker-image.id")
echo -e "${BIYellow}---${RST} Creating container from $id ..."
cid="$(docker create $id bash)"
if [ $? -ne 0 ] ; then
echo -e "${BIRed}!!!${RST} Cannot create container."
exit 1
fi
}
retrieve_build_log () {
create_container
echo -e "${BIYellow}***${RST} Copying build log to ${BIWhite}$openpype_root/build/build.log${RST}"
docker cp "$cid:/opt/openpype/build/build.log" "$openpype_root/build"
}
openpype_root=$(realpath $(dirname $(dirname "${BASH_SOURCE[0]}")))
if [ -z $1 ]; then
dockerfile="Dockerfile"
else
dockerfile="Dockerfile.$1"
if [ ! -f "$openpype_root/$dockerfile" ]; then
echo -e "${BIRed}!!!${RST} Dockerfile for specifed platform ${BIWhite}$1${RST} doesn't exist."
exit 1
else
echo -e "${BIGreen}>>>${RST} Using Dockerfile for ${BIWhite}$1${RST} ..."
fi
fi
# Main
main () {
openpype_root=$(realpath $(dirname $(dirname "${BASH_SOURCE[0]}")))
@ -28,36 +63,35 @@ main () {
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})"
local version_command="import os;exec(open(os.path.join('$openpype_root', 'openpype', 'version.py')).read());print(__version__);"
local openpype_version="$(python3 <<< ${version_command})"
echo -e "${BIGreen}>>>${RST} Running docker build ..."
docker build --pull --no-cache -t pypeclub/openpype:$openpype_version .
# docker build --pull --no-cache -t pypeclub/openpype:$openpype_version .
docker build --pull --iidfile $openpype_root/build/docker-image.id -t pypeclub/openpype:$openpype_version -f $dockerfile .
if [ $? -ne 0 ] ; then
echo $?
echo -e "${BIRed}!!!${RST} Docker build failed."
retrieve_build_log
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
create_container
echo -e "${BIYellow}---${RST} Copying ..."
docker cp "$id:/opt/openpype/build/exe.linux-x86_64-3.7" "$openpype_root/build"
docker cp "$cid:/opt/openpype/build/exe.linux-x86_64-3.7" "$openpype_root/build"
docker cp "$cid:/opt/openpype/build/build.log" "$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)"
local username="$(logname)"
chown -R $username ./build
echo -e "${BIGreen}>>>${RST} All done, you can delete container:"
echo -e "${BIYellow}$id${RST}"
echo -e "${BIYellow}$cid${RST}"
}
return_code=0

View file

@ -20,6 +20,7 @@ import hashlib
import tarfile
import zipfile
import time
import subprocess
term = blessed.Terminal()
@ -65,12 +66,40 @@ def _print(msg: str, message_type: int = 0) -> None:
print("{}{}".format(header, msg))
_print("Processing third-party dependencies ...")
start_time = time.time_ns()
openpype_root = Path(os.path.dirname(__file__)).parent
pyproject = toml.load(openpype_root / "pyproject.toml")
_print("Handling PySide2 Qt framework ...")
pyside2_version = None
try:
pyside2_version = pyproject["openpype"]["pyside2"]["version"]
_print("We'll install PySide2{}".format(pyside2_version))
except AttributeError:
_print("No PySide2 version was specified, using latest available.", 2)
pyside2_arg = "PySide2" if not pyside2_version else "PySide2{}".format(pyside2_version) # noqa: E501
python_vendor_dir = openpype_root / "vendor" / "python"
try:
subprocess.run(
[sys.executable, "-m", "pip", "install", "--upgrade",
pyside2_arg, "-t", str(python_vendor_dir)],
check=True, stdout=subprocess.DEVNULL)
except subprocess.CalledProcessError as e:
_print("Error during PySide2 installation.", 1)
_print(str(e), 1)
sys.exit(1)
# Remove libraries for QtSql which don't have available libraries
# by default and Postgre library would require to modify rpath of dependency
platform_name = platform.system().lower()
if platform_name == "darwin":
pyside2_sqldrivers_dir = (
python_vendor_dir / "PySide2" / "Qt" / "plugins" / "sqldrivers"
)
for filepath in pyside2_sqldrivers_dir.iterdir():
os.remove(str(filepath))
_print("Processing third-party dependencies ...")
try:
thirdparty = pyproject["openpype"]["thirdparty"]

View file

@ -98,4 +98,4 @@ main () {
"$POETRY_HOME/bin/poetry" run python "$openpype_root/tools/fetch_thirdparty_libs.py"
}
main
main

44
tools/parse_pyproject.py Normal file
View file

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
"""Parse pyproject.toml and return its values.
Useful for shell scripts to know more about OpenPype build.
"""
import sys
import os
import toml
from pathlib import Path
import click
@click.command()
@click.argument("keys", nargs=-1, type=click.STRING)
def main(keys):
"""Get values from `pyproject.toml`.
You can specify dot separated keys from `pyproject.toml`
as arguments and this script will return them on separate
lines. If key doesn't exists, None is returned.
"""
openpype_root = Path(os.path.dirname(__file__)).parent
py_project = toml.load(openpype_root / "pyproject.toml")
for q in keys:
query = q.split(".")
data = py_project
for k in query:
if isinstance(data, list):
try:
data = data[int(k)]
except IndexError:
print("None")
sys.exit()
continue
if isinstance(data, dict):
data = data.get(k)
print(data)
if __name__ == "__main__":
main()

View file

@ -19,6 +19,7 @@ We use [CX_Freeze](https://cx-freeze.readthedocs.io/en/latest) to freeze the cod
This is outline of build steps. Most of them are done automatically via scripts:
- Virtual environment is created using **Poetry** in `.venv`
- Necessary python modules outside of `.venv` are stored to `./vendor/python` (like `PySide2`)
- Necessary third-party tools (like [ffmpeg](https://www.ffmpeg.org/), [OpenImageIO](https://github.com/OpenImageIO/oiio)
and [usd libraries](https://developer.nvidia.com/usd)) are downloaded to `./vendor/bin`
- OpenPype code is frozen with **cx_freeze** to `./build`
@ -55,14 +56,14 @@ For development purposes it is possible to run OpenPype directly from the source
To start OpenPype from source you need to
1. Run `.\tools\create_env.ps1` to create virtual environment in `.venv`
2. Run `.\tools\fetch_thirdparty_libs.ps1` to get **ffmpeg**, **oiio** and other tools needed.
2. Run `.\tools\fetch_thirdparty_libs.ps1` to get **PySide2**, **ffmpeg**, **oiio** and other tools needed.
3. 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.
Step 1 and 2 needs to be run only once (or when something was changed).
#### To build OpenPype:
1. Run `.\tools\create_env.ps1` to create virtual environment in `.venv`
2. Run `.\tools\fetch_thirdparty_libs.ps1` to get **ffmpeg**, **oiio** and other tools needed.
2. Run `.\tools\fetch_thirdparty_libs.ps1` to get **PySide2**, **ffmpeg**, **oiio** and other tools needed.
3. `.\tools\build.ps1` to build OpenPype to `.\build`
@ -84,6 +85,13 @@ You can use Docker to build OpenPype. Just run:
```shell
$ sudo ./tools/docker_build.sh
```
This will by default use Debian as base image. If you need to make Centos 7 compatible build, please run:
```sh
sudo ./tools/docker_build.sh centos7
```
and you should have built OpenPype in `build` directory. It is using **Centos 7**
as a base image.
@ -178,7 +186,7 @@ For more information about setting your build environment please refer to [pyenv
#### To build Pype:
1. Run `./tools/create_env.sh` to create virtual environment in `./venv`
2. Run `./tools/fetch_thirdparty_libs.sh` to get **ffmpeg**, **oiio** and other tools needed.
2. Run `./tools/fetch_thirdparty_libs.sh` to get **PySide2**, **ffmpeg**, **oiio** and other tools needed.
3. Run `./tools/build.sh` to build pype executables in `.\build\`
</TabItem>
@ -266,6 +274,19 @@ pywin32 = { version = "300", markers = "sys_platform == 'win32'" }
For more information see [Poetry documentation](https://python-poetry.org/docs/dependency-specification/).
### Python modules as thirdparty
There are some python modules that can be available only in OpenPype and should not be propagated to any subprocess.
Best example is **PySide2** which is required to run OpenPype but can be used only in OpenPype and should not be in PYTHONPATH for most of host applications.
We've decided to separate these breaking dependencies to be able run OpenPype from code and from build the same way.
:::warning
**PySide2** has handled special cases related to it's build process.
### Linux
- We're fixing rpath of shared objects on linux which is modified during cx freeze processing.
### MacOS
- **QtSql** libraries are removed on MacOS because their dependencies are not available and would require to modify rpath of Postgre library.
:::
### Binary dependencies
To add some binary tool or something that doesn't fit standard Python distribution methods, you
can use [fetch_thirdparty_libs](#fetch_thirdparty_libs) script. It will take things defined in
@ -323,14 +344,18 @@ Same as:
poetry run python ./tools/create_zip.py
```
### docker_build.sh
### docker_build.sh *[variant]*
Script to build OpenPype on [Docker](https://www.docker.com/) enabled systems - usually Linux and Windows
with [Docker Desktop](https://docs.docker.com/docker-for-windows/install/)
and [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/about) (WSL) installed.
It must be run with administrative privileges - `sudo ./docker_build.sh`.
It will use **Centos 7** base image to build OpenPype. You'll see your build in `./build` folder.
It will use latest **Debian** base image to build OpenPype. If you need to build OpenPype for
older systems like Centos 7, use `centos7` as argument. This will use another Dockerfile to build
OpenPype with **Centos 7** as base image.
You'll see your build in `./build` folder.
### fetch_thirdparty_libs
This script will download necessary tools for OpenPype defined in `pyproject.toml` like FFMpeg,