Merge branch 'develop' into enhancement/add_missing_repair_action_validate_resolution_setting_3dsmax
|
|
@ -296,12 +296,15 @@ def run(script):
|
|||
@click.option("--mongo_url",
|
||||
help="MongoDB for testing.",
|
||||
default=None)
|
||||
@click.option("--dump_databases",
|
||||
help="Dump all databases to data folder.",
|
||||
default=None)
|
||||
def runtests(folder, mark, pyargs, test_data_folder, persist, app_variant,
|
||||
timeout, setup_only, mongo_url, app_group):
|
||||
timeout, setup_only, mongo_url, app_group, dump_databases):
|
||||
"""Run all automatic tests after proper initialization via start.py"""
|
||||
PypeCommands().run_tests(folder, mark, pyargs, test_data_folder,
|
||||
persist, app_variant, timeout, setup_only,
|
||||
mongo_url, app_group)
|
||||
mongo_url, app_group, dump_databases)
|
||||
|
||||
|
||||
@main.command(help="DEPRECATED - run sync server")
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# AfterEffects Integration
|
||||
|
||||
Requirements: This extension requires use of Javascript engine, which is
|
||||
Requirements: This extension requires use of Javascript engine, which is
|
||||
available since CC 16.0.
|
||||
Please check your File>Project Settings>Expressions>Expressions Engine
|
||||
|
||||
|
|
@ -13,28 +13,26 @@ The After Effects integration requires two components to work; `extension` and `
|
|||
To install the extension download [Extension Manager Command Line tool (ExManCmd)](https://github.com/Adobe-CEP/Getting-Started-guides/tree/master/Package%20Distribute%20Install#option-2---exmancmd).
|
||||
|
||||
```
|
||||
ExManCmd /install {path to addon}/api/extension.zxp
|
||||
ExManCmd /install {path to avalon-core}\avalon\photoshop\extension.zxp
|
||||
```
|
||||
OR
|
||||
download [Anastasiy’s Extension Manager](https://install.anastasiy.com/)
|
||||
|
||||
`{path to addon}` will be most likely in your AppData (on Windows, in your user data folder in Linux and MacOS.)
|
||||
|
||||
### Server
|
||||
|
||||
The easiest way to get the server and After Effects launch is with:
|
||||
|
||||
```
|
||||
python -c ^"import openpype.hosts.photoshop;openpype.hosts..aftereffects.launch(""c:\Program Files\Adobe\Adobe After Effects 2020\Support Files\AfterFX.exe"")^"
|
||||
python -c ^"import avalon.photoshop;avalon.aftereffects.launch(""c:\Program Files\Adobe\Adobe After Effects 2020\Support Files\AfterFX.exe"")^"
|
||||
```
|
||||
|
||||
`avalon.aftereffects.launch` launches the application and server, and also closes the server when After Effects exists.
|
||||
|
||||
## Usage
|
||||
|
||||
The After Effects extension can be found under `Window > Extensions > AYON`. Once launched you should be presented with a panel like this:
|
||||
The After Effects extension can be found under `Window > Extensions > OpenPype`. Once launched you should be presented with a panel like this:
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
## Developing
|
||||
|
|
@ -45,8 +43,8 @@ When developing the extension you can load it [unsigned](https://github.com/Adob
|
|||
When signing the extension you can use this [guide](https://github.com/Adobe-CEP/Getting-Started-guides/tree/master/Package%20Distribute%20Install#package-distribute-install-guide).
|
||||
|
||||
```
|
||||
ZXPSignCmd -selfSignedCert NA NA Ayon Avalon-After-Effects Ayon extension.p12
|
||||
ZXPSignCmd -sign {path to addon}/api/extension {path to addon}/api/extension.zxp extension.p12 Ayon
|
||||
ZXPSignCmd -selfSignedCert NA NA Avalon Avalon-After-Effects avalon extension.p12
|
||||
ZXPSignCmd -sign {path to avalon-core}\avalon\aftereffects\extension {path to avalon-core}\avalon\aftereffects\extension.zxp extension.p12 avalon
|
||||
```
|
||||
|
||||
### Plugin Examples
|
||||
|
|
@ -54,14 +52,14 @@ ZXPSignCmd -sign {path to addon}/api/extension {path to addon}/api/extension.zxp
|
|||
These plugins were made with the [polly config](https://github.com/mindbender-studio/config). To fully integrate and load, you will have to use this config and add `image` to the [integration plugin](https://github.com/mindbender-studio/config/blob/master/polly/plugins/publish/integrate_asset.py).
|
||||
|
||||
Expected deployed extension location on default Windows:
|
||||
`c:\Program Files (x86)\Common Files\Adobe\CEP\extensions\io.ynput.AE.panel`
|
||||
`c:\Program Files (x86)\Common Files\Adobe\CEP\extensions\com.openpype.AE.panel`
|
||||
|
||||
For easier debugging of Javascript:
|
||||
https://community.adobe.com/t5/download-install/adobe-extension-debuger-problem/td-p/10911704?page=1
|
||||
Add (optional) --enable-blink-features=ShadowDOMV0,CustomElementsV0 when starting Chrome
|
||||
then localhost:8092
|
||||
|
||||
Or use Visual Studio Code https://medium.com/adobetech/extendscript-debugger-for-visual-studio-code-public-release-a2ff6161fa01
|
||||
Or use Visual Studio Code https://medium.com/adobetech/extendscript-debugger-for-visual-studio-code-public-release-a2ff6161fa01
|
||||
## Resources
|
||||
- https://javascript-tools-guide.readthedocs.io/introduction/index.html
|
||||
- https://github.com/Adobe-CEP/Getting-Started-guides
|
||||
|
|
|
|||
|
|
@ -1,31 +1,32 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ExtensionList>
|
||||
<Extension Id="io.ynput.AE.panel">
|
||||
<Extension Id="com.openpype.AE.panel">
|
||||
<HostList>
|
||||
|
||||
|
||||
<!-- Comment Host tags according to the apps you want your panel to support -->
|
||||
|
||||
|
||||
<!-- Photoshop -->
|
||||
<Host Name="PHXS" Port="8088"/>
|
||||
|
||||
|
||||
<!-- Illustrator -->
|
||||
<Host Name="ILST" Port="8089"/>
|
||||
|
||||
<!-- InDesign -->
|
||||
<Host Name="IDSN" Port="8090" />
|
||||
|
||||
|
||||
<!-- Premiere -->
|
||||
<Host Name="PPRO" Port="8091" />
|
||||
|
||||
|
||||
<!-- AfterEffects -->
|
||||
<Host Name="AEFT" Port="8092" />
|
||||
|
||||
|
||||
<!-- PRELUDE -->
|
||||
<Host Name="PRLD" Port="8093" />
|
||||
|
||||
|
||||
<!-- FLASH Pro -->
|
||||
<Host Name="FLPR" Port="8094" />
|
||||
|
||||
|
||||
</HostList>
|
||||
</Extension>
|
||||
</ExtensionList>
|
||||
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ExtensionManifest Version="8.0" ExtensionBundleId="io.ynput.AE.panel" ExtensionBundleVersion="1.1.0"
|
||||
ExtensionBundleName="io.ynput.AE.panel" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<ExtensionManifest Version="8.0" ExtensionBundleId="com.openpype.AE.panel" ExtensionBundleVersion="1.0.27"
|
||||
ExtensionBundleName="com.openpype.AE.panel" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<ExtensionList>
|
||||
<Extension Id="io.ynput.AE.panel" Version="1.0" />
|
||||
<Extension Id="com.openpype.AE.panel" Version="1.0" />
|
||||
</ExtensionList>
|
||||
<ExecutionEnvironment>
|
||||
<HostList>
|
||||
|
|
@ -38,7 +38,7 @@
|
|||
</RequiredRuntimeList>
|
||||
</ExecutionEnvironment>
|
||||
<DispatchInfoList>
|
||||
<Extension Id="io.ynput.AE.panel">
|
||||
<Extension Id="com.openpype.AE.panel">
|
||||
<DispatchInfo >
|
||||
<Resources>
|
||||
<MainPath>./index.html</MainPath>
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
</Lifecycle>
|
||||
<UI>
|
||||
<Type>Panel</Type>
|
||||
<Menu>AYON</Menu>
|
||||
<Menu>OpenPype</Menu>
|
||||
<Geometry>
|
||||
<Size>
|
||||
<Height>200</Height>
|
||||
|
|
@ -66,7 +66,7 @@
|
|||
|
||||
</Geometry>
|
||||
<Icons>
|
||||
<Icon Type="Normal">./icons/ayon_logo.png</Icon>
|
||||
<Icon Type="Normal">./icons/iconNormal.png</Icon>
|
||||
<Icon Type="RollOver">./icons/iconRollover.png</Icon>
|
||||
<Icon Type="Disabled">./icons/iconDisabled.png</Icon>
|
||||
<Icon Type="DarkNormal">./icons/iconDarkNormal.png</Icon>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 16 KiB |
BIN
openpype/hosts/aftereffects/api/panel_failure.PNG
Normal file
|
After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
|
@ -2,10 +2,12 @@
|
|||
"""OpenPype startup script."""
|
||||
from openpype.pipeline import install_host
|
||||
from openpype.hosts.houdini.api import HoudiniHost
|
||||
from openpype import AYON_SERVER_ENABLED
|
||||
|
||||
|
||||
def main():
|
||||
print("Installing OpenPype ...")
|
||||
print("Installing {} ...".format(
|
||||
"AYON" if AYON_SERVER_ENABLED else "OpenPype"))
|
||||
install_host(HoudiniHost())
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@
|
|||
"""OpenPype startup script."""
|
||||
from openpype.pipeline import install_host
|
||||
from openpype.hosts.houdini.api import HoudiniHost
|
||||
from openpype import AYON_SERVER_ENABLED
|
||||
|
||||
|
||||
def main():
|
||||
print("Installing OpenPype ...")
|
||||
print("Installing {} ...".format(
|
||||
"AYON" if AYON_SERVER_ENABLED else "OpenPype"))
|
||||
install_host(HoudiniHost())
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@
|
|||
"""OpenPype startup script."""
|
||||
from openpype.pipeline import install_host
|
||||
from openpype.hosts.houdini.api import HoudiniHost
|
||||
from openpype import AYON_SERVER_ENABLED
|
||||
|
||||
|
||||
def main():
|
||||
print("Installing OpenPype ...")
|
||||
print("Installing {} ...".format(
|
||||
"AYON" if AYON_SERVER_ENABLED else "OpenPype"))
|
||||
install_host(HoudiniHost())
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@
|
|||
"""OpenPype startup script."""
|
||||
from openpype.pipeline import install_host
|
||||
from openpype.hosts.houdini.api import HoudiniHost
|
||||
from openpype import AYON_SERVER_ENABLED
|
||||
|
||||
|
||||
def main():
|
||||
print("Installing OpenPype ...")
|
||||
print("Installing {} ...".format(
|
||||
"AYON" if AYON_SERVER_ENABLED else "OpenPype"))
|
||||
install_host(HoudiniHost())
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ from openpype.pipeline import (
|
|||
)
|
||||
from openpype.pipeline.load.utils import get_representation_path_from_context
|
||||
from openpype.pipeline.colorspace import (
|
||||
get_imageio_colorspace_from_filepath,
|
||||
get_imageio_file_rules_colorspace_from_filepath,
|
||||
get_imageio_config,
|
||||
get_imageio_file_rules
|
||||
)
|
||||
|
|
@ -285,10 +285,10 @@ class FileNodeLoader(load.LoaderPlugin):
|
|||
)
|
||||
|
||||
path = get_representation_path_from_context(context)
|
||||
colorspace = get_imageio_colorspace_from_filepath(
|
||||
path=path,
|
||||
host_name=host_name,
|
||||
project_name=project_name,
|
||||
colorspace = get_imageio_file_rules_colorspace_from_filepath(
|
||||
path,
|
||||
host_name,
|
||||
project_name,
|
||||
config_data=config_data,
|
||||
file_rules=file_rules,
|
||||
project_settings=project_settings
|
||||
|
|
|
|||
|
|
@ -371,7 +371,6 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin):
|
|||
continue
|
||||
for node in data["nodes"]:
|
||||
lib.set_attribute(data["attribute"], data["values"][0], node)
|
||||
|
||||
with lib.renderlayer(layer_node):
|
||||
|
||||
# Repair animation must be enabled
|
||||
|
|
@ -392,13 +391,11 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin):
|
|||
if renderer != "renderman":
|
||||
prefix_attr = RenderSettings.get_image_prefix_attr(renderer)
|
||||
fname_prefix = default_prefix
|
||||
cmds.setAttr("{}.{}".format(node, prefix_attr),
|
||||
fname_prefix, type="string")
|
||||
cmds.setAttr(prefix_attr, fname_prefix, type="string")
|
||||
|
||||
# Repair padding
|
||||
padding_attr = RenderSettings.get_padding_attr(renderer)
|
||||
cmds.setAttr("{}.{}".format(node, padding_attr),
|
||||
cls.DEFAULT_PADDING)
|
||||
cmds.setAttr(padding_attr, cls.DEFAULT_PADDING)
|
||||
else:
|
||||
# renderman handles stuff differently
|
||||
cmds.setAttr("rmanGlobals.imageFileFormat",
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ The Photoshop integration requires two components to work; `extension` and `serv
|
|||
To install the extension download [Extension Manager Command Line tool (ExManCmd)](https://github.com/Adobe-CEP/Getting-Started-guides/tree/master/Package%20Distribute%20Install#option-2---exmancmd).
|
||||
|
||||
```
|
||||
ExManCmd /install {path to addon}/api/extension.zxp
|
||||
ExManCmd /install {path to avalon-core}\avalon\photoshop\extension.zxp
|
||||
```
|
||||
|
||||
### Server
|
||||
|
|
@ -17,16 +17,16 @@ ExManCmd /install {path to addon}/api/extension.zxp
|
|||
The easiest way to get the server and Photoshop launch is with:
|
||||
|
||||
```
|
||||
python -c ^"import openpype.hosts.photoshop;openpype.hosts.photoshop.launch(""C:\Program Files\Adobe\Adobe Photoshop 2020\Photoshop.exe"")^"
|
||||
python -c ^"import avalon.photoshop;avalon.photoshop.launch(""C:\Program Files\Adobe\Adobe Photoshop 2020\Photoshop.exe"")^"
|
||||
```
|
||||
|
||||
`avalon.photoshop.launch` launches the application and server, and also closes the server when Photoshop exists.
|
||||
|
||||
## Usage
|
||||
|
||||
The Photoshop extension can be found under `Window > Extensions > Ayon`. Once launched you should be presented with a panel like this:
|
||||
The Photoshop extension can be found under `Window > Extensions > Avalon`. Once launched you should be presented with a panel like this:
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
## Developing
|
||||
|
|
@ -37,7 +37,7 @@ When developing the extension you can load it [unsigned](https://github.com/Adob
|
|||
When signing the extension you can use this [guide](https://github.com/Adobe-CEP/Getting-Started-guides/tree/master/Package%20Distribute%20Install#package-distribute-install-guide).
|
||||
|
||||
```
|
||||
ZXPSignCmd -selfSignedCert NA NA Ayon Ayon-Photoshop Ayon extension.p12
|
||||
ZXPSignCmd -selfSignedCert NA NA Avalon Avalon-Photoshop avalon extension.p12
|
||||
ZXPSignCmd -sign {path to avalon-core}\avalon\photoshop\extension {path to avalon-core}\avalon\photoshop\extension.zxp extension.p12 avalon
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ExtensionList>
|
||||
<Extension Id="io.ynput.PS.panel">
|
||||
<Extension Id="com.openpype.PS.panel">
|
||||
<HostList>
|
||||
<Host Name="PHXS" Port="8078"/>
|
||||
<Host Name="FLPR" Port="8078"/>
|
||||
</HostList>
|
||||
</Extension>
|
||||
</ExtensionList>
|
||||
</ExtensionList>
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<ExtensionManifest ExtensionBundleId="io.ynput.PS.panel" ExtensionBundleVersion="1.1.0" Version="7.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<ExtensionManifest ExtensionBundleId="com.openpype.PS.panel" ExtensionBundleVersion="1.0.12" Version="7.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<ExtensionList>
|
||||
<Extension Id="io.ynput.PS.panel" Version="1.0.1" />
|
||||
<Extension Id="com.openpype.PS.panel" Version="1.0.1" />
|
||||
</ExtensionList>
|
||||
<ExecutionEnvironment>
|
||||
<HostList>
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
</RequiredRuntimeList>
|
||||
</ExecutionEnvironment>
|
||||
<DispatchInfoList>
|
||||
<Extension Id="io.ynput.PS.panel">
|
||||
<Extension Id="com.openpype.PS.panel">
|
||||
<DispatchInfo>
|
||||
<Resources>
|
||||
<MainPath>./index.html</MainPath>
|
||||
|
|
@ -32,7 +32,7 @@
|
|||
</Lifecycle>
|
||||
<UI>
|
||||
<Type>Panel</Type>
|
||||
<Menu>AYON</Menu>
|
||||
<Menu>OpenPype</Menu>
|
||||
<Geometry>
|
||||
<Size>
|
||||
<Width>300</Width>
|
||||
|
|
@ -44,7 +44,7 @@
|
|||
</MaxSize>
|
||||
</Geometry>
|
||||
<Icons>
|
||||
<Icon Type="Normal">./icons/ayon_logo.png</Icon>
|
||||
<Icon Type="Normal">./icons/avalon-logo-48.png</Icon>
|
||||
</Icons>
|
||||
</UI>
|
||||
</DispatchInfo>
|
||||
|
|
|
|||
BIN
openpype/hosts/photoshop/api/extension/icons/avalon-logo-48.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |
BIN
openpype/hosts/photoshop/api/panel.PNG
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
openpype/hosts/photoshop/api/panel_failure.PNG
Normal file
|
After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
|
@ -1,18 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Collect original base name for use in templates."""
|
||||
from pathlib import Path
|
||||
|
||||
import pyblish.api
|
||||
|
||||
|
||||
class CollectOriginalBasename(pyblish.api.InstancePlugin):
|
||||
"""Collect original file base name."""
|
||||
|
||||
order = pyblish.api.CollectorOrder + 0.498
|
||||
label = "Collect Base Name"
|
||||
hosts = ["standalonepublisher"]
|
||||
families = ["simpleUnrealTexture"]
|
||||
|
||||
def process(self, instance):
|
||||
file_name = Path(instance.data["representations"][0]["files"])
|
||||
instance.data["originalBasename"] = file_name.stem
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Validator for correct file naming."""
|
||||
import re
|
||||
import pyblish.api
|
||||
|
||||
from openpype.pipeline.publish import (
|
||||
ValidateContentsOrder,
|
||||
PublishXmlValidationError,
|
||||
)
|
||||
|
||||
|
||||
class ValidateSimpleUnrealTextureNaming(pyblish.api.InstancePlugin):
|
||||
label = "Validate Unreal Texture Names"
|
||||
hosts = ["standalonepublisher"]
|
||||
families = ["simpleUnrealTexture"]
|
||||
order = ValidateContentsOrder
|
||||
regex = "^T_{asset}.*"
|
||||
|
||||
def process(self, instance):
|
||||
file_name = instance.data.get("originalBasename")
|
||||
self.log.info(file_name)
|
||||
pattern = self.regex.format(asset=instance.data.get("asset"))
|
||||
if not re.match(pattern, file_name):
|
||||
msg = f"Invalid file name {file_name}"
|
||||
raise PublishXmlValidationError(
|
||||
self, msg, formatting_data={
|
||||
"invalid_file": file_name,
|
||||
"asset": instance.data.get("asset")
|
||||
})
|
||||
|
|
@ -73,7 +73,7 @@ class CollectRenderInstances(pyblish.api.InstancePlugin):
|
|||
render_layer_id = creator_attributes["render_layer_instance_id"]
|
||||
for in_data in instance.context.data["workfileInstances"]:
|
||||
if (
|
||||
in_data["creator_identifier"] == "render.layer"
|
||||
in_data.get("creator_identifier") == "render.layer"
|
||||
and in_data["instance_id"] == render_layer_id
|
||||
):
|
||||
render_layer_data = in_data
|
||||
|
|
|
|||
|
|
@ -464,8 +464,7 @@ class AbstractSubmitDeadline(pyblish.api.InstancePlugin,
|
|||
self.log.info("Submitted job to Deadline: {}.".format(job_id))
|
||||
|
||||
# TODO: Find a way that's more generic and not render type specific
|
||||
export_job = instance.data["exportJob"]
|
||||
if export_job:
|
||||
if "exportJob" in instance.data:
|
||||
self.log.info("Splitting export and render in two jobs")
|
||||
self.log.info("Export job id: %s", job_id)
|
||||
render_job_info = self.get_job_info(dependency_job_ids=[job_id])
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
"""Collect default Deadline server."""
|
||||
import pyblish.api
|
||||
|
||||
from openpype import AYON_SERVER_ENABLED
|
||||
|
||||
|
||||
class CollectDefaultDeadlineServer(pyblish.api.ContextPlugin):
|
||||
"""Collect default Deadline Webservice URL.
|
||||
|
|
@ -30,24 +32,26 @@ class CollectDefaultDeadlineServer(pyblish.api.ContextPlugin):
|
|||
self.log.error("Cannot get OpenPype Deadline module.")
|
||||
raise AssertionError("OpenPype Deadline module not found.")
|
||||
|
||||
# get default deadline webservice url from deadline module
|
||||
self.log.debug(deadline_module.deadline_urls)
|
||||
context.data["defaultDeadline"] = deadline_module.deadline_urls["default"] # noqa: E501
|
||||
deadline_settings = context.data["project_settings"]["deadline"]
|
||||
deadline_server_name = None
|
||||
if AYON_SERVER_ENABLED:
|
||||
deadline_server_name = deadline_settings["deadline_server"]
|
||||
else:
|
||||
deadline_servers = deadline_settings["deadline_servers"]
|
||||
if deadline_servers:
|
||||
deadline_server_name = deadline_servers[0]
|
||||
|
||||
context.data["deadlinePassMongoUrl"] = self.pass_mongo_url
|
||||
context.data["deadlinePassMongoUrl"] = self.pass_mongo_url
|
||||
|
||||
deadline_servers = (context.data
|
||||
["project_settings"]
|
||||
["deadline"]
|
||||
["deadline_servers"])
|
||||
if deadline_servers:
|
||||
deadline_server_name = deadline_servers[0]
|
||||
deadline_webservice = None
|
||||
if deadline_server_name:
|
||||
deadline_webservice = deadline_module.deadline_urls.get(
|
||||
deadline_server_name)
|
||||
if deadline_webservice:
|
||||
context.data["defaultDeadline"] = deadline_webservice
|
||||
self.log.debug("Overriding from project settings with {}".format( # noqa: E501
|
||||
deadline_webservice))
|
||||
|
||||
context.data["defaultDeadline"] = \
|
||||
context.data["defaultDeadline"].strip().rstrip("/")
|
||||
default_deadline_webservice = deadline_module.deadline_urls["default"]
|
||||
deadline_webservice = (
|
||||
deadline_webservice
|
||||
or default_deadline_webservice
|
||||
)
|
||||
|
||||
context.data["defaultDeadline"] = deadline_webservice.strip().rstrip("/") # noqa
|
||||
|
|
|
|||
|
|
@ -137,7 +137,6 @@ class IntegrateAsset(pyblish.api.InstancePlugin):
|
|||
"mvUsd",
|
||||
"mvUsdComposition",
|
||||
"mvUsdOverride",
|
||||
"simpleUnrealTexture",
|
||||
"online",
|
||||
"uasset",
|
||||
"blendScene",
|
||||
|
|
|
|||
|
|
@ -185,8 +185,7 @@ class PypeCommands:
|
|||
task,
|
||||
app,
|
||||
env_group=env_group,
|
||||
launch_type=LaunchTypes.farm_render,
|
||||
env={}
|
||||
launch_type=LaunchTypes.farm_render
|
||||
)
|
||||
else:
|
||||
env = os.environ.copy()
|
||||
|
|
@ -215,7 +214,7 @@ class PypeCommands:
|
|||
|
||||
def run_tests(self, folder, mark, pyargs,
|
||||
test_data_folder, persist, app_variant, timeout, setup_only,
|
||||
mongo_url, app_group):
|
||||
mongo_url, app_group, dump_databases):
|
||||
"""
|
||||
Runs tests from 'folder'
|
||||
|
||||
|
|
@ -276,6 +275,13 @@ class PypeCommands:
|
|||
if mongo_url:
|
||||
args.extend(["--mongo_url", mongo_url])
|
||||
|
||||
if dump_databases:
|
||||
msg = "dump_databases format is not recognized: {}".format(
|
||||
dump_databases
|
||||
)
|
||||
assert dump_databases in ["bson", "json"], msg
|
||||
args.extend(["--dump_databases", dump_databases])
|
||||
|
||||
print("run_tests args: {}".format(args))
|
||||
import pytest
|
||||
pytest.main(args)
|
||||
|
|
|
|||
|
|
@ -38,16 +38,6 @@
|
|||
"file": "{subset}_{@version}<_{output}><.{@frame}>.{ext}",
|
||||
"path": "{@folder}/{@file}"
|
||||
},
|
||||
"simpleUnrealTextureHero": {
|
||||
"folder": "{root[work]}/{project[name]}/{hierarchy}/{asset}/publish/{family}/hero",
|
||||
"file": "{originalBasename}.{ext}",
|
||||
"path": "{@folder}/{@file}"
|
||||
},
|
||||
"simpleUnrealTexture": {
|
||||
"folder": "{root[work]}/{project[name]}/{hierarchy}/{asset}/publish/{family}/{@version}",
|
||||
"file": "{originalBasename}_{@version}.{ext}",
|
||||
"path": "{@folder}/{@file}"
|
||||
},
|
||||
"online": {
|
||||
"folder": "{root[work]}/{project[name]}/{hierarchy}/{asset}/publish/{family}/{subset}/{@version}",
|
||||
"file": "{originalBasename}<.{@frame}><_{udim}>.{ext}",
|
||||
|
|
@ -68,8 +58,6 @@
|
|||
},
|
||||
"__dynamic_keys_labels__": {
|
||||
"maya2unreal": "Maya to Unreal",
|
||||
"simpleUnrealTextureHero": "Simple Unreal Texture - Hero",
|
||||
"simpleUnrealTexture": "Simple Unreal Texture",
|
||||
"online": "online",
|
||||
"tycache": "tycache",
|
||||
"source": "source",
|
||||
|
|
|
|||
|
|
@ -322,22 +322,9 @@
|
|||
"animation",
|
||||
"setdress",
|
||||
"layout",
|
||||
"mayaScene",
|
||||
"simpleUnrealTexture"
|
||||
"mayaScene"
|
||||
],
|
||||
"template_name_profiles": [
|
||||
{
|
||||
"families": [
|
||||
"simpleUnrealTexture"
|
||||
],
|
||||
"hosts": [
|
||||
"standalonepublisher"
|
||||
],
|
||||
"task_types": [],
|
||||
"task_names": [],
|
||||
"template_name": "simpleUnrealTextureHero"
|
||||
}
|
||||
]
|
||||
"template_name_profiles": []
|
||||
},
|
||||
"CleanUp": {
|
||||
"paterns": [],
|
||||
|
|
@ -519,17 +506,6 @@
|
|||
"task_names": [],
|
||||
"template_name": "render"
|
||||
},
|
||||
{
|
||||
"families": [
|
||||
"simpleUnrealTexture"
|
||||
],
|
||||
"hosts": [
|
||||
"standalonepublisher"
|
||||
],
|
||||
"task_types": [],
|
||||
"task_names": [],
|
||||
"template_name": "simpleUnrealTexture"
|
||||
},
|
||||
{
|
||||
"families": [
|
||||
"staticMesh",
|
||||
|
|
@ -565,19 +541,7 @@
|
|||
"template_name": "tycache"
|
||||
}
|
||||
],
|
||||
"hero_template_name_profiles": [
|
||||
{
|
||||
"families": [
|
||||
"simpleUnrealTexture"
|
||||
],
|
||||
"hosts": [
|
||||
"standalonepublisher"
|
||||
],
|
||||
"task_types": [],
|
||||
"task_names": [],
|
||||
"template_name": "simpleUnrealTextureHero"
|
||||
}
|
||||
],
|
||||
"hero_template_name_profiles": [],
|
||||
"custom_staging_dir_profiles": []
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -133,14 +133,6 @@
|
|||
],
|
||||
"help": "Texture files with UDIM together with worfile"
|
||||
},
|
||||
"create_simple_unreal_texture": {
|
||||
"name": "simple_unreal_texture",
|
||||
"label": "Simple Unreal Texture",
|
||||
"family": "simpleUnrealTexture",
|
||||
"icon": "Image",
|
||||
"defaults": [],
|
||||
"help": "Texture files with Unreal naming convention"
|
||||
},
|
||||
"create_vdb": {
|
||||
"name": "vdb",
|
||||
"label": "VDB Volumetric Data",
|
||||
|
|
|
|||
|
|
@ -244,19 +244,6 @@
|
|||
".hda"
|
||||
]
|
||||
},
|
||||
{
|
||||
"family": "simpleUnrealTexture",
|
||||
"identifier": "",
|
||||
"label": "Simple UE texture",
|
||||
"icon": "fa.image",
|
||||
"default_variants": [],
|
||||
"description": "Simple Unreal Engine texture",
|
||||
"detailed_description": "Texture files with Unreal Engine naming conventions",
|
||||
"allow_sequences": false,
|
||||
"allow_multiple_items": true,
|
||||
"allow_version_control": false,
|
||||
"extensions": []
|
||||
},
|
||||
{
|
||||
"family": "audio",
|
||||
"identifier": "",
|
||||
|
|
|
|||
|
|
@ -632,6 +632,14 @@ class TrayManager:
|
|||
self.exit()
|
||||
|
||||
elif result.restart or result.token_changed:
|
||||
# Remove environment variables from current connection
|
||||
# - keep develop, staging, headless values
|
||||
for key in {
|
||||
"AYON_SERVER_URL",
|
||||
"AYON_API_KEY",
|
||||
"AYON_BUNDLE_NAME",
|
||||
}:
|
||||
os.environ.pop(key, None)
|
||||
self.restart()
|
||||
|
||||
def _on_restart_action(self):
|
||||
|
|
|
|||
|
|
@ -14,15 +14,35 @@ class ServerListSubmodel(BaseSettingsModel):
|
|||
value: str = Field(title="Value")
|
||||
|
||||
|
||||
async def defined_deadline_ws_name_enum_resolver(
|
||||
addon: "BaseServerAddon",
|
||||
settings_variant: str = "production",
|
||||
project_name: str | None = None,
|
||||
) -> list[str]:
|
||||
"""Provides list of names of configured Deadline webservice urls."""
|
||||
if addon is None:
|
||||
return []
|
||||
|
||||
settings = await addon.get_studio_settings(variant=settings_variant)
|
||||
|
||||
ws_urls = []
|
||||
for deadline_url_item in settings.deadline_urls:
|
||||
ws_urls.append(deadline_url_item.name)
|
||||
|
||||
return ws_urls
|
||||
|
||||
|
||||
class DeadlineSettings(BaseSettingsModel):
|
||||
deadline_urls: list[ServerListSubmodel] = Field(
|
||||
default_factory=list,
|
||||
title="System Deadline Webservice URLs",
|
||||
scope=["studio"],
|
||||
)
|
||||
deadline_servers: list[str] = Field(
|
||||
title="Project deadline servers",
|
||||
deadline_server: str = Field(
|
||||
title="Project deadline server",
|
||||
section="---",
|
||||
scope=["project"],
|
||||
enum_resolver=defined_deadline_ws_name_enum_resolver
|
||||
)
|
||||
publish: PublishPluginsModel = Field(
|
||||
default_factory=PublishPluginsModel,
|
||||
|
|
@ -42,7 +62,6 @@ DEFAULT_VALUES = {
|
|||
"value": "http://127.0.0.1:8082"
|
||||
}
|
||||
],
|
||||
# TODO: this needs to be dynamic from "deadline_urls"
|
||||
"deadline_servers": [],
|
||||
"deadline_server": "default",
|
||||
"publish": DEFAULT_DEADLINE_PLUGINS_SETTINGS
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,6 @@ from pydantic import Field, validator
|
|||
from ayon_server.settings import BaseSettingsModel, ensure_unique_names
|
||||
|
||||
|
||||
class CollectDefaultDeadlineServerModel(BaseSettingsModel):
|
||||
"""Settings for event handlers running in ftrack service."""
|
||||
|
||||
pass_mongo_url: bool = Field(title="Pass Mongo url to job")
|
||||
|
||||
|
||||
class CollectDeadlinePoolsModel(BaseSettingsModel):
|
||||
"""Settings Deadline default pools."""
|
||||
|
||||
|
|
@ -286,12 +280,6 @@ class ProcessSubmittedJobOnFarmModel(BaseSettingsModel):
|
|||
|
||||
|
||||
class PublishPluginsModel(BaseSettingsModel):
|
||||
CollectDefaultDeadlineServer: CollectDefaultDeadlineServerModel = Field(
|
||||
default_factory=CollectDefaultDeadlineServerModel,
|
||||
title="Default Deadline Webservice")
|
||||
CollectDefaultDeadlineServer: CollectDefaultDeadlineServerModel = Field(
|
||||
default_factory=CollectDefaultDeadlineServerModel,
|
||||
title="Default Deadline Webservice")
|
||||
CollectDeadlinePools: CollectDeadlinePoolsModel = Field(
|
||||
default_factory=CollectDeadlinePoolsModel,
|
||||
title="Default Pools")
|
||||
|
|
@ -332,9 +320,6 @@ class PublishPluginsModel(BaseSettingsModel):
|
|||
|
||||
|
||||
DEFAULT_DEADLINE_PLUGINS_SETTINGS = {
|
||||
"CollectDefaultDeadlineServer": {
|
||||
"pass_mongo_url": True
|
||||
},
|
||||
"CollectDeadlinePools": {
|
||||
"primary_pool": "",
|
||||
"secondary_pool": ""
|
||||
|
|
|
|||
|
|
@ -39,6 +39,11 @@ def pytest_addoption(parser):
|
|||
help="Provide url of the Mongo database."
|
||||
)
|
||||
|
||||
parser.addoption(
|
||||
"--dump_databases", action="store", default=None,
|
||||
help="Dump databases to data folder."
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def test_data_folder(request):
|
||||
|
|
@ -75,6 +80,11 @@ def mongo_url(request):
|
|||
return request.config.getoption("--mongo_url")
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def dump_databases(request):
|
||||
return request.config.getoption("--dump_databases")
|
||||
|
||||
|
||||
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
|
||||
def pytest_runtest_makereport(item, call):
|
||||
# execute all other hooks to obtain the report object
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ Command line arguments
|
|||
- "--timeout" - "Provide specific timeout value for test case",
|
||||
- "--setup_only" - "Only create dbs, do not run tests",
|
||||
- "--mongo_url" - "MongoDB for testing.",
|
||||
|
||||
- "--dump_databases" - ("json"|"bson") export database in expected format after successful test (to output folder in temp location - which is made persistent by this, must be cleared manually)
|
||||
Run Tray for test
|
||||
-----------------
|
||||
In case of failed test you might want to run it manually and visually debug what happened.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Helper class for automatic testing, provides dump and restore via command
|
||||
line utilities.
|
||||
|
||||
Expect mongodump, mongoimport and mongorestore present at PATH
|
||||
Expect mongodump, mongoexport, mongoimport and mongorestore present at PATH
|
||||
"""
|
||||
import os
|
||||
import pymongo
|
||||
|
|
@ -148,7 +148,7 @@ class DBHandler:
|
|||
self.client.drop_database(db_name)
|
||||
|
||||
def backup_to_dump(self, db_name, dump_dir, overwrite=False,
|
||||
collection=None):
|
||||
collection=None, format="bson"):
|
||||
"""
|
||||
Helper method for running mongodump for specific 'db_name'
|
||||
"""
|
||||
|
|
@ -160,15 +160,24 @@ class DBHandler:
|
|||
raise RuntimeError("Backup already exists, "
|
||||
"run with overwrite=True")
|
||||
|
||||
query = self._dump_query(self.uri, dump_dir,
|
||||
db_name=db_name, collection=collection)
|
||||
print("Mongodump query:: {}".format(query))
|
||||
subprocess.run(query)
|
||||
collections = [collection]
|
||||
if format == "json" and collection is None:
|
||||
collections = self.client[db_name].list_collection_names()
|
||||
|
||||
for collection in collections:
|
||||
query = self._dump_query(self.uri, dump_dir,
|
||||
db_name=db_name, collection=collection,
|
||||
format=format)
|
||||
print("Mongodump query:: {}".format(query))
|
||||
process = subprocess.run(query)
|
||||
assert process.returncode == 0, "Mongo dump failed."
|
||||
|
||||
def _db_exists(self, db_name):
|
||||
return db_name in self.client.list_database_names()
|
||||
|
||||
def _dump_query(self, uri, output_path, db_name=None, collection=None):
|
||||
def _dump_query(
|
||||
self, uri, output_path, db_name=None, collection=None, format="bson"
|
||||
):
|
||||
"""Prepares dump query based on 'db_name' or 'collection'."""
|
||||
db_part = coll_part = ""
|
||||
if db_name:
|
||||
|
|
@ -177,11 +186,22 @@ class DBHandler:
|
|||
if not db_name:
|
||||
raise ValueError("db_name must be present")
|
||||
coll_part = "--collection={}".format(collection)
|
||||
query = "\"{}\" --uri=\"{}\" --out={} {} {}".format(
|
||||
"mongodump", uri, output_path, db_part, coll_part
|
||||
)
|
||||
|
||||
return query
|
||||
tool = "mongodump"
|
||||
query = "{} --uri=\"{}\""
|
||||
|
||||
if format == "json":
|
||||
assert collection, "Collection is needed for json export."
|
||||
|
||||
query += " --jsonArray --pretty"
|
||||
tool = "mongoexport"
|
||||
output_path = os.path.join(
|
||||
output_path, "{}.{}.json".format(db_name, collection)
|
||||
)
|
||||
|
||||
query += " --out={} {} {}"
|
||||
|
||||
return query.format(tool, uri, output_path, db_part, coll_part)
|
||||
|
||||
def _restore_query(self, uri, dump_dir,
|
||||
db_name=None, db_name_out=None,
|
||||
|
|
|
|||
|
|
@ -70,7 +70,9 @@ class ModuleUnitTest(BaseTest):
|
|||
)
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def download_test_data(self, test_data_folder, persist, request):
|
||||
def download_test_data(
|
||||
self, test_data_folder, persist, request, dump_databases
|
||||
):
|
||||
test_data_folder = test_data_folder or self.TEST_DATA_FOLDER
|
||||
if test_data_folder:
|
||||
print("Using existing folder {}".format(test_data_folder))
|
||||
|
|
@ -100,13 +102,13 @@ class ModuleUnitTest(BaseTest):
|
|||
if ext and ext.lstrip('.') in handler_class.IMPLEMENTED_ZIP_FORMATS: # noqa: E501
|
||||
handler_class.unzip(os.path.join(tmpdir, file_name))
|
||||
|
||||
yield tmpdir
|
||||
yield tmpdir
|
||||
|
||||
persist = (persist or self.PERSIST or
|
||||
self.is_test_failed(request))
|
||||
if not persist:
|
||||
print("Removing {}".format(tmpdir))
|
||||
shutil.rmtree(tmpdir)
|
||||
persist = (persist or self.PERSIST or
|
||||
self.is_test_failed(request) or dump_databases)
|
||||
if not persist:
|
||||
print("Removing {}".format(tmpdir))
|
||||
shutil.rmtree(tmpdir)
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def output_folder_url(self, download_test_data):
|
||||
|
|
@ -163,7 +165,7 @@ class ModuleUnitTest(BaseTest):
|
|||
|
||||
@pytest.fixture(scope="module")
|
||||
def db_setup(self, download_test_data, env_var, monkeypatch_session,
|
||||
request, mongo_url):
|
||||
request, mongo_url, dump_databases, persist):
|
||||
"""Restore prepared MongoDB dumps into selected DB."""
|
||||
backup_dir = os.path.join(download_test_data, "input", "dumps")
|
||||
uri = os.environ.get("OPENPYPE_MONGO")
|
||||
|
|
@ -178,7 +180,17 @@ class ModuleUnitTest(BaseTest):
|
|||
|
||||
yield db_handler
|
||||
|
||||
persist = self.PERSIST or self.is_test_failed(request)
|
||||
if dump_databases:
|
||||
print("Dumping databases to {}".format(download_test_data))
|
||||
output_dir = os.path.join(download_test_data, "output", "dumps")
|
||||
db_handler.backup_to_dump(
|
||||
self.TEST_DB_NAME, output_dir, format=dump_databases
|
||||
)
|
||||
db_handler.backup_to_dump(
|
||||
self.TEST_OPENPYPE_NAME, output_dir, format=dump_databases
|
||||
)
|
||||
|
||||
persist = persist or self.PERSIST or self.is_test_failed(request)
|
||||
if not persist:
|
||||
db_handler.teardown(self.TEST_DB_NAME)
|
||||
db_handler.teardown(self.TEST_OPENPYPE_NAME)
|
||||
|
|
|
|||