Source code for dazpy._element

from __future__ import annotations

import json

from ._script_builder import ScriptBuilder


[docs] class DazElement: """Generic proxy for any DzElement subclass. Base class for all typed proxies. You normally do not instantiate ``DazElement`` directly. Use the typed subclasses (:class:`~dazpy.DazNode`, :class:`~dazpy.DazMaterial`, etc.) returned by :class:`~dazpy.DazScene` and related helpers instead. Args: client: The :class:`~dazpy.DazClient` used for all remote calls. locator: A JavaScript expression that evaluates to the underlying ``DzElement`` instance inside DAZ Studio. """ def __init__(self, client: "DazClient", locator: str): # noqa: F821 object.__setattr__(self, "_client", client) object.__setattr__(self, "_locator", locator) object.__setattr__(self, "_cache", {})
[docs] def get_property(self, label: str) -> object: """Return the current value of a property looked up by its display label. Args: label: The ``getLabel()`` string of the ``DzProperty``. Returns: The property value, or ``None`` if the property does not exist. """ script = ScriptBuilder.iife(f""" var obj = {self._locator}; if (!obj) return null; var prop = obj.findPropertyByLabel({json.dumps(label)}); if (!prop) return null; return prop.getValue(); """) return self._client.execute(script).value
[docs] def set_property(self, label: str, value: object) -> None: """Set a property value by display label. Args: label: The ``getLabel()`` string of the ``DzProperty``. value: The new value. Must be JSON-serialisable. """ serialized = ScriptBuilder.serialize_arg(value) script = ScriptBuilder.iife(f""" var obj = {self._locator}; if (!obj) return {{"error": "not_found"}}; var prop = obj.findPropertyByLabel({json.dumps(label)}); if (!prop) return {{"error": "property_not_found"}}; prop.setValue({serialized}); return {{"success": true}}; """) self._client.execute(script)
[docs] def set_properties(self, values: dict[str, object]) -> dict[str, bool]: """Set multiple property values by display label in one call. Args: values: ``{label: value}``. Each value must be JSON-serialisable. Returns: ``{label: True}`` for labels that resolved to a real property and were written, ``{label: False}`` for labels that did not resolve. """ data_json = json.dumps(values) script = ScriptBuilder.iife(f""" var obj = {self._locator}; if (!obj) return null; var _data = {data_json}; var _result = {{}}; for (var _label in _data) {{ if (!_data.hasOwnProperty(_label)) continue; var prop = obj.findPropertyByLabel(_label); if (prop) {{ prop.setValue(_data[_label]); _result[_label] = true; }} else {{ _result[_label] = false; }} }} return _result; """) return self._client.execute(script).value or {}
[docs] def list_properties(self) -> list[dict]: """Return metadata for every property on this element. Returns: A list of dicts, each with keys ``"label"``, ``"name"``, and ``"type"`` (the DazScript class name of the property). """ script = ScriptBuilder.iife(f""" var obj = {self._locator}; if (!obj) return null; var result = []; for (var i = 0; i < obj.getNumProperties(); i++) {{ var p = obj.getProperty(i); result.push({{"label": p.getLabel(), "name": p.getName(), "type": p.className()}}); }} return result; """) return self._client.execute(script).value or []
[docs] def numeric_properties(self) -> dict[str, object]: """Return every numeric property on this element as ``{label: value}``. Unlike :meth:`list_properties`, this fetches labels and current values for all numeric (float/int/bool) properties in a single HTTP round-trip — use it instead of calling :meth:`get_property` in a loop over ``list_properties()`` results. Returns: A dict mapping each numeric property's display label to its current value. """ script = ScriptBuilder.iife(f""" var obj = {self._locator}; if (!obj) return null; var result = {{}}; for (var i = 0; i < obj.getNumProperties(); i++) {{ var p = obj.getProperty(i); if (p.inherits("DzNumericProperty")) {{ result[p.getLabel()] = p.getValue(); }} }} return result; """) return self._client.execute(script).value or {}
@property def class_name(self) -> str | None: """The DazScript class name of this element (e.g. ``"DzFigure"``, ``"DzSpotLight"``).""" script = ScriptBuilder.iife( f"var obj = {self._locator}; return obj ? obj.className() : null;" ) return self._client.execute(script).value
[docs] def snapshot(self, fields: list[str]) -> dict: """Read and cache a set of property values in a single call. Args: fields: Property labels to read. Returns: A dict mapping each label to its current value. Missing owner or missing property both resolve to ``None`` for the affected label(s). """ cache = object.__getattribute__(self, "_cache") fields_json = json.dumps(fields) script = ScriptBuilder.iife(f""" var obj = {self._locator}; if (!obj) return null; var _fields = {fields_json}; var _result = {{}}; for (var i = 0; i < _fields.length; i++) {{ var prop = obj.findPropertyByLabel(_fields[i]); _result[_fields[i]] = prop ? prop.getValue() : null; }} return _result; """) values = self._client.execute(script).value or {} for field in fields: cache[field] = values.get(field) return {f: cache[f] for f in fields}
[docs] def refresh(self) -> None: """Clear the local property cache so the next read fetches live data.""" object.__getattribute__(self, "_cache").clear()