Skip to content

rr_job

Python wrapper for RoyalRender XML job file.

RREnvList

Bases: dict

Source code in client/ayon_royalrender/rr_job.py
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class RREnvList(dict):
    def serialize(self):
        # <rrEnvList>VariableA=ValueA~~~VariableB=ValueB</rrEnvList>
        return "~~~".join(
            ["{}={}".format(k, v) for k, v in sorted(self.items())])

    @staticmethod
    def parse(data):
        # type: (str) -> RREnvList
        """Parse rrEnvList string and return it as RREnvList object."""
        out = RREnvList()
        for var in data.split("~~~"):
            k, v = var.split("=", maxsplit=1)
            out[k] = v
        return out

parse(data) staticmethod

Parse rrEnvList string and return it as RREnvList object.

Source code in client/ayon_royalrender/rr_job.py
29
30
31
32
33
34
35
36
37
@staticmethod
def parse(data):
    # type: (str) -> RREnvList
    """Parse rrEnvList string and return it as RREnvList object."""
    out = RREnvList()
    for var in data.split("~~~"):
        k, v = var.split("=", maxsplit=1)
        out[k] = v
    return out

RRJob

Bases: object

Mapping of Royal Render job file to a data class.

Source code in client/ayon_royalrender/rr_job.py
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
@attr.s
class RRJob(object):
    """Mapping of Royal Render job file to a data class."""

    # Required
    # --------

    # Name of your render application. Same as in the render config file.
    # (Maya, Softimage)
    Software = attr.ib()  # type: str

    # The OS the scene was created on, all texture paths are set on
    # that OS. Possible values are windows, linux, osx
    SceneOS = attr.ib()  # type: str

    # Renderer you use. Same as in the render config file
    # (VRay, Mental Ray, Arnold)
    Renderer = attr.ib()  # type: str

    # Version you want to render with. (5.11, 2010, 12)
    Version = attr.ib()  # type: str

    # Name of the scene file with full path.
    SceneName = attr.ib()  # type: str

    # Is the job enabled for submission?
    # enabled by default
    IsActive = attr.ib()  # type: bool

    # Sequence settings of this job
    SeqStart = attr.ib()  # type: int
    SeqEnd = attr.ib()  # type: int
    SeqStep = attr.ib()  # type: int
    SeqFileOffset = attr.ib()  # type: int

    # If you specify ImageDir, then ImageFilename has no path. If you do
    # NOT specify ImageDir, then ImageFilename has to include the path.
    # Same for ImageExtension.
    # Important: Do not forget any _ or . in front or after the frame
    # numbering. Usually ImageExtension always starts with a . (.tga, .exr)
    ImageDir = attr.ib()  # type: str
    ImageFilename = attr.ib()  # type: str
    ImageExtension = attr.ib()  # type: str
    # option to ouput more than one render path/node.
    ChannelFilename = attr.ib() # type: str
    ChannelExtension = attr.ib() # type: str
    # Some applications always add a . or _ in front of the frame number.
    # Set this variable to that character. The user can then change
    # the filename at the rrSubmitter and the submitter keeps
    # track of this character.
    ImagePreNumberLetter = attr.ib()  # type: str

    # If you render a single file, e.g. Quicktime or Avi, then you have to
    # set this value. Videos have to be rendered at once on one client.
    ImageSingleOutputFile = attr.ib(default=False)  # type: bool

    # Semi-Required (required for some render applications)
    # -----------------------------------------------------

    # The database of your scene file. In Maya and XSI called "project",
    # in Lightwave "content dir"
    SceneDatabaseDir = attr.ib(default=None)  # type: str

    # Required if you want to split frames on multiple clients
    ImageWidth = attr.ib(default=None)  # type: int
    ImageHeight = attr.ib(default=None)  # type: int
    Camera = attr.ib(default=None)  # type: str
    Layer = attr.ib(default=None)  # type: str
    Channel = attr.ib(default=None)  # type: str

    # Optional
    # --------

    # Used for the RR render license function.
    # E.g. If you render with mentalRay, then add mentalRay. If you render
    # with Nuke and you use Furnace plugins in your comp, add Furnace.
    # TODO: determine how this work for multiple plugins
    RequiredPlugins = attr.ib(default=None)  # type: str

    # Frame Padding of the frame number in the rendered filename.
    # Some render config files are setting the padding at render time.
    ImageFramePadding = attr.ib(default=None)  # type: int

    # Some render applications support overriding the image format at
    # the render commandline.
    OverrideImageFormat = attr.ib(default=None)  # type: str

    # rrControl can display the name of additonal channels that are
    # rendered. Each channel requires these two values. ChannelFilename
    # contains the full path.
    ChannelFilename = attr.ib(default=None)  # type: str
    ChannelExtension = attr.ib(default=None)  # type: str

    # A value between 0 and 255. Each job gets the Pre ID attached as small
    # letter to the main ID. A new main ID is generated for every machine
    # for every 5/1000s.
    PreID = attr.ib(default=None)  # type: int

    # When the job is received by the server, the server checks for other
    # jobs send from this machine. If a job with the PreID was found, then
    # this jobs waits for the other job. Note: This flag can be used multiple
    # times to wait for multiple jobs.
    WaitForPreIDs = attr.ib(factory=list)  # type: list

    # List of submitter options per job
    # list item must be of `SubmitterParameter` type
    SubmitterParameters = attr.ib(factory=list)  # type: list

    # List of Custom job attributes
    # Royal Render support custom attributes in format <CustomFoo> or
    # <CustomSomeOtherAttr>
    # list item must be of `CustomAttribute` named tuple
    CustomAttributes = attr.ib(factory=list)  # type: list

    # This is used to hold command line arguments for Execute job
    CustomAddCmdFlags = attr.ib(default=None)  # type: str

    # Additional information for subsequent publish script and
    # for better display in rrControl
    UserName = attr.ib(default=None)  # type: str
    CustomSeQName = attr.ib(default=None)  # type: str
    CustomSHotName = attr.ib(default=None)  # type: str
    CustomVersionName = attr.ib(default=None)  # type: str
    CustomUserInfo = attr.ib(default=None)  # type: str
    SubmitMachine = attr.ib(default=None)  # type: str
    Color_ID = attr.ib(default=2)  # type: int
    CompanyProjectName = attr.ib(default=None)  # type: str

    RequiredLicenses = attr.ib(default=None)  # type: str

    # Additional frame info
    Priority = attr.ib(default=50)  # type: int
    TotalFrames = attr.ib(default=None)  # type: int
    Tiled = attr.ib(default=None)  # type: str

    # Environment
    # only used in RR 8.3 and newer
    rrEnvList = attr.ib(default=None, type=str)  # type: str
    rrEnvFile = attr.ib(default=None, type=str)  # type: str

SubmitFile

Bases: object

Class wrapping Royal Render submission XML file.

Source code in client/ayon_royalrender/rr_job.py
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
@attr.s
class SubmitFile(object):
    """Class wrapping Royal Render submission XML file."""

    # Syntax version of the submission file.
    syntax_version = attr.ib(default="6.0")  # type: str

    # Delete submission file after processing
    DeleteXML = attr.ib(default=1)  # type: int

    # List of the submitter options per job.
    # list item must be of `SubmitterParameter` type
    SubmitterParameters = attr.ib(factory=list)  # type: list

    # List of the jobs in submission batch.
    # list item must be of type `RRJob`
    Jobs = attr.ib(factory=list)  # type: list

    @staticmethod
    def _process_submitter_parameters(parameters, dom, append_to):
        # type: (list[SubmitterParameter], md.Document, md.Element) -> None
        """Take list of :class:`SubmitterParameter` and process it as XML.

        This will take :class:`SubmitterParameter`, create XML element
        for them and convert value to Royal Render compatible string
        (options and values separated by ~)

        Args:
            parameters (list of SubmitterParameter): List of parameters.
            dom (xml.dom.minidom.Document): XML Document
            append_to (xml.dom.minidom.Element): Element to append to.

        """
        for param in parameters:
            if not isinstance(param, SubmitterParameter):
                raise AttributeError(
                    "{} is not of type `SubmitterParameter`".format(param))
            xml_parameter = dom.createElement("SubmitterParameter")
            xml_parameter.appendChild(dom.createTextNode(param.serialize()))
            append_to.appendChild(xml_parameter)

    def serialize(self):
        # type: () -> str
        """Return all data serialized as XML.

        Returns:
            str: XML data as string.

        """
        def filter_data(a, v):
            """Skip private attributes."""
            if a.name.startswith("_"):
                return False
            if v is None:
                return False
            return True

        root = md.Document()
        # root element: <RR_Job_File syntax_version="6.0">
        job_file = root.createElement('RR_Job_File')
        job_file.setAttribute("syntax_version", self.syntax_version)

        # handle Submitter Parameters for batch
        # <SubmitterParameter>foo=bar~baz~goo</SubmitterParameter>
        self._process_submitter_parameters(
            self.SubmitterParameters, root, job_file)
        root.appendChild(job_file)
        for job in self.Jobs:  # type: RRJob
            if not isinstance(job, RRJob):
                raise AttributeError(
                    "{} is not of type `SubmitterParameter`".format(job))
            xml_job = root.createElement("Job")
            # handle Submitter Parameters for job
            self._process_submitter_parameters(
                job.SubmitterParameters, root, xml_job
            )
            job_custom_attributes = job.CustomAttributes

            serialized_job = attr.asdict(
                job, dict_factory=OrderedDict, filter=filter_data)
            serialized_job.pop("CustomAttributes")
            serialized_job.pop("SubmitterParameters")
            # we are handling `WaitForPreIDs` separately.
            wait_pre_ids = serialized_job.pop("WaitForPreIDs", [])

            for custom_attr in job_custom_attributes:  # type: CustomAttribute
                serialized_job["Custom{}".format(
                    custom_attr.name)] = custom_attr.value

            for item, value in serialized_job.items():
                xml_attr = root.createElement(item)
                xml_attr.appendChild(
                    root.createTextNode(str(value))
                )
                xml_job.appendChild(xml_attr)

            # WaitForPreID - can be used multiple times
            for pre_id in wait_pre_ids:
                xml_attr = root.createElement("WaitForPreID")
                xml_attr.appendChild(
                    root.createTextNode(str(pre_id))
                )
                xml_job.appendChild(xml_attr)

            job_file.appendChild(xml_job)

        return root.toprettyxml(indent="\t")

serialize()

Return all data serialized as XML.

Returns:

Name Type Description
str

XML data as string.

Source code in client/ayon_royalrender/rr_job.py
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
def serialize(self):
    # type: () -> str
    """Return all data serialized as XML.

    Returns:
        str: XML data as string.

    """
    def filter_data(a, v):
        """Skip private attributes."""
        if a.name.startswith("_"):
            return False
        if v is None:
            return False
        return True

    root = md.Document()
    # root element: <RR_Job_File syntax_version="6.0">
    job_file = root.createElement('RR_Job_File')
    job_file.setAttribute("syntax_version", self.syntax_version)

    # handle Submitter Parameters for batch
    # <SubmitterParameter>foo=bar~baz~goo</SubmitterParameter>
    self._process_submitter_parameters(
        self.SubmitterParameters, root, job_file)
    root.appendChild(job_file)
    for job in self.Jobs:  # type: RRJob
        if not isinstance(job, RRJob):
            raise AttributeError(
                "{} is not of type `SubmitterParameter`".format(job))
        xml_job = root.createElement("Job")
        # handle Submitter Parameters for job
        self._process_submitter_parameters(
            job.SubmitterParameters, root, xml_job
        )
        job_custom_attributes = job.CustomAttributes

        serialized_job = attr.asdict(
            job, dict_factory=OrderedDict, filter=filter_data)
        serialized_job.pop("CustomAttributes")
        serialized_job.pop("SubmitterParameters")
        # we are handling `WaitForPreIDs` separately.
        wait_pre_ids = serialized_job.pop("WaitForPreIDs", [])

        for custom_attr in job_custom_attributes:  # type: CustomAttribute
            serialized_job["Custom{}".format(
                custom_attr.name)] = custom_attr.value

        for item, value in serialized_job.items():
            xml_attr = root.createElement(item)
            xml_attr.appendChild(
                root.createTextNode(str(value))
            )
            xml_job.appendChild(xml_attr)

        # WaitForPreID - can be used multiple times
        for pre_id in wait_pre_ids:
            xml_attr = root.createElement("WaitForPreID")
            xml_attr.appendChild(
                root.createTextNode(str(pre_id))
            )
            xml_job.appendChild(xml_attr)

        job_file.appendChild(xml_job)

    return root.toprettyxml(indent="\t")

SubmitterParameter

Wrapper for Submitter Parameters.

Source code in client/ayon_royalrender/rr_job.py
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
class SubmitterParameter:
    """Wrapper for Submitter Parameters."""
    def __init__(self, parameter, *args):
        # type: (str, list) -> None
        self._parameter = parameter
        self._values = args

    def serialize(self):
        # type: () -> str
        """Serialize submitter parameter as a string value.

        This can be later on used as text node in job xml file.

        Returns:
            str: concatenated string of parameter values.

        """
        if len(self._values) > 0:
            return "{param}={val}".format(
                param=self._parameter, val="~".join(self._values))

        return "{param}".format(
                param=self._parameter)

serialize()

Serialize submitter parameter as a string value.

This can be later on used as text node in job xml file.

Returns:

Name Type Description
str

concatenated string of parameter values.

Source code in client/ayon_royalrender/rr_job.py
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
def serialize(self):
    # type: () -> str
    """Serialize submitter parameter as a string value.

    This can be later on used as text node in job xml file.

    Returns:
        str: concatenated string of parameter values.

    """
    if len(self._values) > 0:
        return "{param}={val}".format(
            param=self._parameter, val="~".join(self._values))

    return "{param}".format(
            param=self._parameter)

get_rr_platform()

Returns name of platform used in rr jobs.

Source code in client/ayon_royalrender/rr_job.py
12
13
14
15
16
17
18
19
20
def get_rr_platform():
    # type: () -> str
    """Returns name of platform used in rr jobs."""
    if sys.platform.lower() in ["win32", "win64"]:
        return "windows"
    elif sys.platform.lower() == "darwin":
        return "mac"
    else:
        return "linux"