diff --git a/openpype/hosts/standalonepublisher/plugins/publish/help/validate_frame_ranges.xml b/openpype/hosts/standalonepublisher/plugins/publish/help/validate_frame_ranges.xml
new file mode 100644
index 0000000000..933df1c7c5
--- /dev/null
+++ b/openpype/hosts/standalonepublisher/plugins/publish/help/validate_frame_ranges.xml
@@ -0,0 +1,15 @@
+
+
+
+Invalid frame range
+
+## Invalid frame range
+
+Expected duration or '{duration}' frames set in database, workfile contains only '{found}' frames.
+
+### How to repair?
+
+Modify configuration in the database or tweak frame range in the workfile.
+
+
+
\ No newline at end of file
diff --git a/openpype/hosts/standalonepublisher/plugins/publish/help/validate_shot_duplicates.xml b/openpype/hosts/standalonepublisher/plugins/publish/help/validate_shot_duplicates.xml
new file mode 100644
index 0000000000..77b8727162
--- /dev/null
+++ b/openpype/hosts/standalonepublisher/plugins/publish/help/validate_shot_duplicates.xml
@@ -0,0 +1,15 @@
+
+
+
+Duplicate shots
+
+## Duplicate shot names
+
+Process contains duplicated shot names '{duplicates_str}'.
+
+### How to repair?
+
+Remove shot duplicates.
+
+
+
\ No newline at end of file
diff --git a/openpype/hosts/standalonepublisher/plugins/publish/help/validate_sources.xml b/openpype/hosts/standalonepublisher/plugins/publish/help/validate_sources.xml
new file mode 100644
index 0000000000..d527d2173e
--- /dev/null
+++ b/openpype/hosts/standalonepublisher/plugins/publish/help/validate_sources.xml
@@ -0,0 +1,16 @@
+
+
+
+Files not found
+
+## Source files not found
+
+Process contains duplicated shot names:
+'{files_not_found}'
+
+### How to repair?
+
+Add missing files or run Publish again to collect new publishable files.
+
+
+
\ No newline at end of file
diff --git a/openpype/hosts/standalonepublisher/plugins/publish/help/validate_task_existence.xml b/openpype/hosts/standalonepublisher/plugins/publish/help/validate_task_existence.xml
new file mode 100644
index 0000000000..a943f560d0
--- /dev/null
+++ b/openpype/hosts/standalonepublisher/plugins/publish/help/validate_task_existence.xml
@@ -0,0 +1,16 @@
+
+
+
+Task not found
+
+## Task not found in database
+
+Process contains tasks that don't exist in database:
+'{task_not_found}'
+
+### How to repair?
+
+Remove set task or add task into database into proper place.
+
+
+
\ No newline at end of file
diff --git a/openpype/hosts/standalonepublisher/plugins/publish/help/validate_texture_batch.xml b/openpype/hosts/standalonepublisher/plugins/publish/help/validate_texture_batch.xml
new file mode 100644
index 0000000000..a645df8d02
--- /dev/null
+++ b/openpype/hosts/standalonepublisher/plugins/publish/help/validate_texture_batch.xml
@@ -0,0 +1,15 @@
+
+
+
+No texture files found
+
+## Batch doesn't contain texture files
+
+Batch must contain at least one texture file.
+
+### How to repair?
+
+Add texture file to the batch or check name if it follows naming convention to match texture files to the batch.
+
+
+
\ No newline at end of file
diff --git a/openpype/hosts/standalonepublisher/plugins/publish/help/validate_texture_has_workfile.xml b/openpype/hosts/standalonepublisher/plugins/publish/help/validate_texture_has_workfile.xml
new file mode 100644
index 0000000000..077987a96d
--- /dev/null
+++ b/openpype/hosts/standalonepublisher/plugins/publish/help/validate_texture_has_workfile.xml
@@ -0,0 +1,15 @@
+
+
+
+No workfile found
+
+## Batch should contain workfile
+
+It is expected that published contains workfile that served as a source for textures.
+
+### How to repair?
+
+Add workfile to the batch, or disable this validator if you do not want workfile published.
+
+
+
\ No newline at end of file
diff --git a/openpype/hosts/standalonepublisher/plugins/publish/help/validate_texture_name.xml b/openpype/hosts/standalonepublisher/plugins/publish/help/validate_texture_name.xml
new file mode 100644
index 0000000000..2610917736
--- /dev/null
+++ b/openpype/hosts/standalonepublisher/plugins/publish/help/validate_texture_name.xml
@@ -0,0 +1,32 @@
+
+
+
+Asset name not found
+
+## Couldn't parse asset name from a file
+
+Unable to parse asset name from '{file_name}'. File name doesn't match configured naming convention.
+
+### How to repair?
+
+Check Settings: project_settings/standalonepublisher/publish/CollectTextures for naming convention.
+
+
+### __Detailed Info__ (optional)
+
+This error happens when parsing cannot figure out name of asset texture files belong under.
+
+
+
+Missing keys
+
+## Texture file name is missing some required keys
+
+Texture '{file_name}' is missing values for {missing_str} keys.
+
+### How to repair?
+
+Fix name of texture file and Publish again.
+
+
+
diff --git a/openpype/hosts/standalonepublisher/plugins/publish/help/validate_texture_versions.xml b/openpype/hosts/standalonepublisher/plugins/publish/help/validate_texture_versions.xml
new file mode 100644
index 0000000000..1e536e604f
--- /dev/null
+++ b/openpype/hosts/standalonepublisher/plugins/publish/help/validate_texture_versions.xml
@@ -0,0 +1,35 @@
+
+
+
+Texture version
+
+## Texture version mismatch with workfile
+
+Workfile '{file_name}' version doesn't match with '{version}' of a texture.
+
+### How to repair?
+
+Rename either workfile or texture to contain matching versions
+
+
+### __Detailed Info__ (optional)
+
+This might happen if you are trying to publish textures for older version of workfile (or the other way).
+(Eg. publishing 'workfile_v001' and 'texture_file_v002')
+
+
+
+Too many versions
+
+## Too many versions published at same time
+
+It is currently expected to publish only batch with single version.
+
+Found {found} versions.
+
+### How to repair?
+
+Please remove files with different version and split publishing into multiple steps.
+
+
+
diff --git a/openpype/hosts/standalonepublisher/plugins/publish/help/validate_texture_workfiles.xml b/openpype/hosts/standalonepublisher/plugins/publish/help/validate_texture_workfiles.xml
new file mode 100644
index 0000000000..8187eb0bc8
--- /dev/null
+++ b/openpype/hosts/standalonepublisher/plugins/publish/help/validate_texture_workfiles.xml
@@ -0,0 +1,23 @@
+
+
+
+No secondary workfile
+
+## No secondary workfile found
+
+Current process expects that primary workfile (for example with a extension '{extension}') will contain also 'secondary' workfile.
+
+Secondary workfile for '{file_name}' wasn't found.
+
+### How to repair?
+
+Attach secondary workfile or disable this validator and Publish again.
+
+
+### __Detailed Info__ (optional)
+
+This process was implemented for a possible use case of first workfile coming from Mari, secondary workfile for textures from Substance.
+Publish should contain both if primary workfile is present.
+
+
+
diff --git a/openpype/hosts/standalonepublisher/plugins/publish/validate_frame_ranges.py b/openpype/hosts/standalonepublisher/plugins/publish/validate_frame_ranges.py
index 943cb73b98..c7a2e755b6 100644
--- a/openpype/hosts/standalonepublisher/plugins/publish/validate_frame_ranges.py
+++ b/openpype/hosts/standalonepublisher/plugins/publish/validate_frame_ranges.py
@@ -1,8 +1,10 @@
import re
import pyblish.api
+
import openpype.api
from openpype import lib
+from openpype.pipeline import PublishXmlValidationError
class ValidateFrameRange(pyblish.api.InstancePlugin):
@@ -48,9 +50,15 @@ class ValidateFrameRange(pyblish.api.InstancePlugin):
files = [files]
frames = len(files)
- err_msg = "Frame duration from DB:'{}' ". format(int(duration)) +\
- " doesn't match number of files:'{}'".format(frames) +\
- " Please change frame range for Asset or limit no. of files"
- assert frames == duration, err_msg
+ msg = "Frame duration from DB:'{}' ". format(int(duration)) +\
+ " doesn't match number of files:'{}'".format(frames) +\
+ " Please change frame range for Asset or limit no. of files"
- self.log.debug("Valid ranges {} - {}".format(int(duration), frames))
+ formatting_data = {"duration": duration,
+ "found": frames}
+ if frames == duration:
+ raise PublishXmlValidationError(self, msg,
+ formatting_data=formatting_data)
+
+ self.log.debug("Valid ranges expected '{}' - found '{}'".
+ format(int(duration), frames))
diff --git a/openpype/hosts/standalonepublisher/plugins/publish/validate_shot_duplicates.py b/openpype/hosts/standalonepublisher/plugins/publish/validate_shot_duplicates.py
index 85ec9379ce..0f957acad6 100644
--- a/openpype/hosts/standalonepublisher/plugins/publish/validate_shot_duplicates.py
+++ b/openpype/hosts/standalonepublisher/plugins/publish/validate_shot_duplicates.py
@@ -1,6 +1,7 @@
import pyblish.api
-import openpype.api
+import openpype.api
+from openpype.pipeline import PublishXmlValidationError
class ValidateShotDuplicates(pyblish.api.ContextPlugin):
"""Validating no duplicate names are in context."""
@@ -20,4 +21,8 @@ class ValidateShotDuplicates(pyblish.api.ContextPlugin):
shot_names.append(name)
msg = "There are duplicate shot names:\n{}".format(duplicate_names)
- assert not duplicate_names, msg
+
+ formatting_data = {"duplicate_str": ','.join(duplicate_names)}
+ if duplicate_names:
+ raise PublishXmlValidationError(self, msg,
+ formatting_data=formatting_data)
diff --git a/openpype/hosts/standalonepublisher/plugins/publish/validate_sources.py b/openpype/hosts/standalonepublisher/plugins/publish/validate_sources.py
index eec675e97f..316f58988f 100644
--- a/openpype/hosts/standalonepublisher/plugins/publish/validate_sources.py
+++ b/openpype/hosts/standalonepublisher/plugins/publish/validate_sources.py
@@ -1,8 +1,10 @@
-import pyblish.api
-import openpype.api
-
import os
+import pyblish.api
+
+import openpype.api
+from openpype.pipeline import PublishXmlValidationError
+
class ValidateSources(pyblish.api.InstancePlugin):
"""Validates source files.
@@ -11,7 +13,6 @@ class ValidateSources(pyblish.api.InstancePlugin):
got deleted between starting of SP and now.
"""
-
order = openpype.api.ValidateContentsOrder
label = "Check source files"
@@ -22,6 +23,7 @@ class ValidateSources(pyblish.api.InstancePlugin):
def process(self, instance):
self.log.info("instance {}".format(instance.data))
+ missing_files = set()
for repre in instance.data.get("representations") or []:
files = []
if isinstance(repre["files"], str):
@@ -34,4 +36,10 @@ class ValidateSources(pyblish.api.InstancePlugin):
file_name)
if not os.path.exists(source_file):
- raise ValueError("File {} not found".format(source_file))
+ missing_files.add(source_file)
+
+ msg = "Files '{}' not found".format(','.join(missing_files))
+ formatting_data = {"files_not_found": ' - {}'.join(missing_files)}
+ if missing_files:
+ raise PublishXmlValidationError(self, msg,
+ formatting_data=formatting_data)
diff --git a/openpype/hosts/standalonepublisher/plugins/publish/validate_task_existence.py b/openpype/hosts/standalonepublisher/plugins/publish/validate_task_existence.py
index e3b2ae1646..825092c81b 100644
--- a/openpype/hosts/standalonepublisher/plugins/publish/validate_task_existence.py
+++ b/openpype/hosts/standalonepublisher/plugins/publish/validate_task_existence.py
@@ -1,6 +1,8 @@
import pyblish.api
from avalon import io
+from openpype.pipeline import PublishXmlValidationError
+
class ValidateTaskExistence(pyblish.api.ContextPlugin):
"""Validating tasks on instances are filled and existing."""
@@ -53,4 +55,9 @@ class ValidateTaskExistence(pyblish.api.ContextPlugin):
"Asset: \"{}\" Task: \"{}\"".format(*missing_pair)
)
- raise AssertionError(msg.format("\n".join(pair_msgs)))
+ msg = msg.format("\n".join(pair_msgs))
+
+ formatting_data = {"task_not_found": ' - {}'.join(pair_msgs)}
+ if pair_msgs:
+ raise PublishXmlValidationError(self, msg,
+ formatting_data=formatting_data)
diff --git a/openpype/hosts/standalonepublisher/plugins/publish/validate_texture_batch.py b/openpype/hosts/standalonepublisher/plugins/publish/validate_texture_batch.py
index d592a4a059..d66fb257bb 100644
--- a/openpype/hosts/standalonepublisher/plugins/publish/validate_texture_batch.py
+++ b/openpype/hosts/standalonepublisher/plugins/publish/validate_texture_batch.py
@@ -1,6 +1,8 @@
import pyblish.api
import openpype.api
+from openpype.pipeline import PublishXmlValidationError
+
class ValidateTextureBatch(pyblish.api.InstancePlugin):
"""Validates that some texture files are present."""
@@ -15,8 +17,10 @@ class ValidateTextureBatch(pyblish.api.InstancePlugin):
present = False
for instance in instance.context:
if instance.data["family"] == "textures":
- self.log.info("Some textures present.")
+ self.log.info("At least some textures present.")
return
- assert present, "No textures found in published batch!"
+ msg = "No textures found in published batch!"
+ if not present:
+ raise PublishXmlValidationError(self, msg)
diff --git a/openpype/hosts/standalonepublisher/plugins/publish/validate_texture_has_workfile.py b/openpype/hosts/standalonepublisher/plugins/publish/validate_texture_has_workfile.py
index 7cd540668c..0e67464f59 100644
--- a/openpype/hosts/standalonepublisher/plugins/publish/validate_texture_has_workfile.py
+++ b/openpype/hosts/standalonepublisher/plugins/publish/validate_texture_has_workfile.py
@@ -1,5 +1,7 @@
import pyblish.api
+
import openpype.api
+from openpype.pipeline import PublishXmlValidationError
class ValidateTextureHasWorkfile(pyblish.api.InstancePlugin):
@@ -17,4 +19,6 @@ class ValidateTextureHasWorkfile(pyblish.api.InstancePlugin):
def process(self, instance):
wfile = instance.data["versionData"].get("workfile")
- assert wfile, "Textures are missing attached workfile"
+ msg = "Textures are missing attached workfile"
+ if not wfile:
+ raise PublishXmlValidationError(self, msg)
diff --git a/openpype/hosts/standalonepublisher/plugins/publish/validate_texture_name.py b/openpype/hosts/standalonepublisher/plugins/publish/validate_texture_name.py
index f210be3631..751ad917ca 100644
--- a/openpype/hosts/standalonepublisher/plugins/publish/validate_texture_name.py
+++ b/openpype/hosts/standalonepublisher/plugins/publish/validate_texture_name.py
@@ -1,6 +1,7 @@
import pyblish.api
-import openpype.api
+import openpype.api
+from openpype.pipeline import PublishXmlValidationError
class ValidateTextureBatchNaming(pyblish.api.InstancePlugin):
"""Validates that all instances had properly formatted name."""
@@ -16,12 +17,16 @@ class ValidateTextureBatchNaming(pyblish.api.InstancePlugin):
if isinstance(file_name, list):
file_name = file_name[0]
- msg = "Couldnt find asset name in '{}'\n".format(file_name) + \
+ msg = "Couldn't find asset name in '{}'\n".format(file_name) + \
"File name doesn't follow configured pattern.\n" + \
"Please rename the file."
- assert "NOT_AVAIL" not in instance.data["asset_build"], msg
- instance.data.pop("asset_build")
+ formatting_data = {"file_name": file_name}
+ if "NOT_AVAIL" in instance.data["asset_build"]:
+ raise PublishXmlValidationError(self, msg,
+ formatting_data=formatting_data)
+
+ instance.data.pop("asset_build") # not needed anymore
if instance.data["family"] == "textures":
file_name = instance.data["representations"][0]["files"][0]
@@ -47,4 +52,10 @@ class ValidateTextureBatchNaming(pyblish.api.InstancePlugin):
"Name of the texture file doesn't match expected pattern.\n" + \
"Please rename file(s) {}".format(file_name)
- assert not missing_key_values, msg
+ missing_str = ','.join(["'{}'".format(key)
+ for key in missing_key_values])
+ formatting_data = {"file_name": file_name,
+ "missing_str": missing_str}
+ if missing_key_values:
+ raise PublishXmlValidationError(self, msg, key="missing_values",
+ formatting_data=formatting_data)
diff --git a/openpype/hosts/standalonepublisher/plugins/publish/validate_texture_versions.py b/openpype/hosts/standalonepublisher/plugins/publish/validate_texture_versions.py
index 90d0e8e512..84d9def895 100644
--- a/openpype/hosts/standalonepublisher/plugins/publish/validate_texture_versions.py
+++ b/openpype/hosts/standalonepublisher/plugins/publish/validate_texture_versions.py
@@ -1,5 +1,7 @@
import pyblish.api
+
import openpype.api
+from openpype.pipeline import PublishXmlValidationError
class ValidateTextureBatchVersions(pyblish.api.InstancePlugin):
@@ -25,14 +27,21 @@ class ValidateTextureBatchVersions(pyblish.api.InstancePlugin):
self.log.info("No workfile present for textures")
return
- msg = "Not matching version: texture v{:03d} - workfile {}"
- assert version_str in wfile, \
+ if version_str not in wfile:
+ msg = "Not matching version: texture v{:03d} - workfile {}"
msg.format(
instance.data["version"], wfile
)
+ raise PublishXmlValidationError(self, msg)
present_versions = set()
for instance in instance.context:
present_versions.add(instance.data["version"])
- assert len(present_versions) == 1, "Too many versions in a batch!"
+ if len(present_versions) != 1:
+ msg = "Too many versions in a batch!"
+ found = ','.join(["'{}'".format(val) for val in present_versions])
+ formatting_data = {"found": found}
+
+ raise PublishXmlValidationError(self, msg, key="too_many",
+ formatting_data=formatting_data)
diff --git a/openpype/hosts/standalonepublisher/plugins/publish/validate_texture_workfiles.py b/openpype/hosts/standalonepublisher/plugins/publish/validate_texture_workfiles.py
index 25bb5aea4a..fa492a80d8 100644
--- a/openpype/hosts/standalonepublisher/plugins/publish/validate_texture_workfiles.py
+++ b/openpype/hosts/standalonepublisher/plugins/publish/validate_texture_workfiles.py
@@ -1,11 +1,13 @@
import pyblish.api
+
import openpype.api
+from openpype.pipeline import PublishXmlValidationError
class ValidateTextureBatchWorkfiles(pyblish.api.InstancePlugin):
"""Validates that textures workfile has collected resources (optional).
- Collected recourses means secondary workfiles (in most cases).
+ Collected resources means secondary workfiles (in most cases).
"""
label = "Validate Texture Workfile Has Resources"
@@ -24,6 +26,13 @@ class ValidateTextureBatchWorkfiles(pyblish.api.InstancePlugin):
self.log.warning("Only secondary workfile present!")
return
- msg = "No secondary workfiles present for workfile {}".\
- format(instance.data["name"])
- assert instance.data.get("resources"), msg
+ if not instance.data.get("resources"):
+ msg = "No secondary workfile present for workfile '{}'". \
+ format(instance.data["name"])
+ ext = self.main_workfile_extensions[0]
+ formatting_data = {"file_name": instance.data["name"],
+ "extension": ext}
+
+ raise PublishXmlValidationError(self, msg,
+ formatting_data=formatting_data
+ )