[docs]
class DazError(Exception):
"""Base class for all dazpy exceptions."""
[docs]
class ConnectionError(DazError):
"""Raised when the SDK cannot reach the DAZ Studio Script Server."""
[docs]
class AuthenticationError(DazError):
"""Raised on HTTP 401 or 403 (bad or missing API token, or IP blocked)."""
[docs]
class DazBusyError(DazError):
"""Base class for transient "DAZ Studio is busy, please retry" conditions.
Attributes:
reason: Human-readable explanation of why the server is busy.
retry_after: Server-suggested seconds to wait before retrying.
"""
def __init__(self, message: str, reason: str = "", retry_after: float = 2.0):
super().__init__(message)
self.reason = reason
self.retry_after = retry_after
[docs]
class StudioBusyError(DazBusyError):
"""Raised on HTTP 503 STUDIO_BUSY: DAZ Studio's main thread is occupied
with a scene load, save, clear, or render and cannot service the request."""
[docs]
class ConcurrencyLimitError(DazBusyError):
"""Raised on HTTP 429 CONCURRENT_LIMIT_EXCEEDED: too many requests are
already in flight against the server."""
[docs]
class ScriptError(DazError):
"""Base class for errors that originate inside a DazScript execution.
Attributes:
script: The DazScript source that was submitted (may be empty for
file-based executions).
request_id: The server-assigned request ID, useful for log correlation.
output: Lines written to the DAZ Studio message log before the error
(e.g. via print()), useful for tracing state leading up to a failure.
"""
def __init__(
self,
message: str,
script: str = "",
request_id: str = "",
output: "list[str] | None" = None,
):
super().__init__(message)
self.script = script
self.request_id = request_id
self.output = output or []
@property
def diagnostic(self) -> str:
"""Return a formatted string with line-numbered source and error details."""
lines = []
if self.script:
numbered = "\n".join(f"{i+1:4d}: {line}" for i, line in enumerate(self.script.splitlines()))
lines.append(numbered)
lines.append(str(self))
if self.output:
lines.append("\nCaptured output:\n" + "\n".join(self.output))
if self.request_id:
lines.append(f"request_id: {self.request_id}")
return "\n".join(lines)
[docs]
class ScriptSyntaxError(ScriptError):
"""Raised when the DazScript engine reports a parse / syntax error."""
[docs]
class ScriptRuntimeError(ScriptError):
"""Raised when a DazScript execution fails at runtime (TypeError, ReferenceError, etc.)."""
[docs]
class TimeoutError(DazError):
"""Raised when an HTTP request or async poll exceeds its timeout."""
[docs]
class NodeNotFoundError(DazError):
"""Raised when a requested scene node, bone, or skeleton cannot be found."""
[docs]
class AsyncExecutionError(DazError):
"""Raised when an async request fails, is cancelled, or times out while polling.
Attributes:
request_id: The server-assigned request ID of the failed async job.
"""
def __init__(self, message: str, request_id: str = ""):
super().__init__(message)
self.request_id = request_id
[docs]
class RenderError(DazError):
"""Raised when a render job fails on the DAZ Studio side.
Attributes:
request_id: The server-assigned render request ID.
"""
def __init__(self, message: str, request_id: str = ""):
super().__init__(message)
self.request_id = request_id
[docs]
class BatchLimitExceededError(DazError):
"""Raised by :meth:`~dazpy.Batch.execute` (or ``add_operation``, for the
operation-count limit) when a batch would exceed its configured
operation-count or generated-script-length limit.
Raised client-side before any HTTP call, so an oversized batch never
reaches Studio's main thread.
"""
[docs]
class MaterialError(DazError):
"""Raised when an Iray material/surface-property operation fails.
Covers a missing material, a channel label that doesn't resolve to a
property on the live material, or a failed ``setValue()``/``setMap()``.
Attributes:
request_id: The server-assigned render request ID.
"""
def __init__(self, message: str, request_id: str = ""):
super().__init__(message)
self.request_id = request_id