deadline-cloud-for-nuke 0.18.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. deadline/nuke_adaptor/NukeAdaptor/NukeAdaptor.json +3 -0
  2. deadline/nuke_adaptor/NukeAdaptor/__init__.py +9 -0
  3. deadline/nuke_adaptor/NukeAdaptor/__main__.py +37 -0
  4. deadline/nuke_adaptor/NukeAdaptor/adaptor.py +491 -0
  5. deadline/nuke_adaptor/NukeAdaptor/py.typed +1 -0
  6. deadline/nuke_adaptor/NukeAdaptor/schemas/init_data.schema.json +25 -0
  7. deadline/nuke_adaptor/NukeAdaptor/schemas/run_data.schema.json +9 -0
  8. deadline/nuke_adaptor/NukeClient/__init__.py +6 -0
  9. deadline/nuke_adaptor/NukeClient/nuke_client.py +166 -0
  10. deadline/nuke_adaptor/NukeClient/nuke_handler.py +263 -0
  11. deadline/nuke_adaptor/NukeClient/py.typed +1 -0
  12. deadline/nuke_adaptor/__init__.py +1 -0
  13. deadline/nuke_adaptor/_version.py +16 -0
  14. deadline/nuke_submitter/__init__.py +15 -0
  15. deadline/nuke_submitter/_logging.py +55 -0
  16. deadline/nuke_submitter/_version.py +16 -0
  17. deadline/nuke_submitter/adaptor_override_environment.yaml +84 -0
  18. deadline/nuke_submitter/assets.py +154 -0
  19. deadline/nuke_submitter/data_classes.py +77 -0
  20. deadline/nuke_submitter/deadline_submitter_for_nuke.py +356 -0
  21. deadline/nuke_submitter/default_nuke_job_template.yaml +123 -0
  22. deadline/nuke_submitter/job_bundle_output_test_runner.py +327 -0
  23. deadline/nuke_submitter/py.typed +1 -0
  24. deadline/nuke_submitter/ui/__init__.py +1 -0
  25. deadline/nuke_submitter/ui/components/__init__.py +1 -0
  26. deadline/nuke_submitter/ui/components/scene_settings_tab.py +115 -0
  27. deadline/nuke_util/__init__.py +1 -0
  28. deadline/nuke_util/_version.py +16 -0
  29. deadline/nuke_util/ocio.py +57 -0
  30. deadline_cloud_for_nuke-0.18.0.dist-info/METADATA +98 -0
  31. deadline_cloud_for_nuke-0.18.0.dist-info/RECORD +35 -0
  32. deadline_cloud_for_nuke-0.18.0.dist-info/WHEEL +4 -0
  33. deadline_cloud_for_nuke-0.18.0.dist-info/entry_points.txt +3 -0
  34. deadline_cloud_for_nuke-0.18.0.dist-info/licenses/LICENSE +175 -0
  35. deadline_cloud_for_nuke-0.18.0.dist-info/licenses/NOTICE +1 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ "log_level": "INFO"
3
+ }
@@ -0,0 +1,9 @@
1
+ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+
3
+ from .__main__ import main
4
+ from .adaptor import NukeAdaptor
5
+
6
+ __all__ = [
7
+ "NukeAdaptor",
8
+ "main",
9
+ ]
@@ -0,0 +1,37 @@
1
+ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+
3
+ import logging
4
+ import sys
5
+ import typing
6
+ import pathlib
7
+
8
+ from openjd.adaptor_runtime import EntryPoint
9
+
10
+ from .adaptor import NukeAdaptor
11
+
12
+ __all__ = ["main"]
13
+ _logger = logging.getLogger(__name__)
14
+
15
+
16
+ def main(reentry_exe: typing.Optional[pathlib.Path] = None) -> int:
17
+ """
18
+ Entry point for the Nuke Adaptor
19
+ """
20
+ _logger.info("About to start the NukeAdaptor")
21
+
22
+ package_name = vars(sys.modules[__name__])["__package__"]
23
+ if not package_name:
24
+ raise RuntimeError(f"Must be run as a module. Do not run {__file__} directly")
25
+
26
+ try:
27
+ EntryPoint(NukeAdaptor).start(reentry_exe=reentry_exe)
28
+ except Exception as e:
29
+ _logger.error(f"Entrypoint failed: {e}")
30
+ return 1
31
+
32
+ _logger.info("Done NukeAdaptor main")
33
+ return 0
34
+
35
+
36
+ if __name__ == "__main__":
37
+ sys.exit(main())
@@ -0,0 +1,491 @@
1
+ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ import os
7
+ import re
8
+ import sys
9
+ import threading
10
+ import time
11
+ import jsonschema # type: ignore
12
+ from typing import Callable, cast
13
+
14
+ from deadline.client.api import get_deadline_cloud_library_telemetry_client, TelemetryClient
15
+ from openjd.adaptor_runtime._version import version as openjd_adaptor_version
16
+ from openjd.adaptor_runtime.adaptors import Adaptor, AdaptorDataValidators, SemanticVersion
17
+ from openjd.adaptor_runtime_client import Action
18
+ from openjd.adaptor_runtime.process import LoggingSubprocess
19
+ from openjd.adaptor_runtime.app_handlers import RegexCallback, RegexHandler
20
+ from openjd.adaptor_runtime.application_ipc import ActionsQueue, AdaptorServer
21
+
22
+ from .._version import version as adaptor_version
23
+
24
+ _logger = logging.getLogger(__name__)
25
+
26
+
27
+ class NukeNotRunningError(Exception):
28
+ """Error that is raised when attempting to use Nuke while it is not running"""
29
+
30
+ pass
31
+
32
+
33
+ # Actions which must be queued before any others
34
+ _FIRST_NUKE_ACTIONS = ["script_file"]
35
+ _NUKE_INIT_KEYS = {
36
+ "continue_on_error",
37
+ "proxy",
38
+ "write_nodes",
39
+ "views",
40
+ }
41
+
42
+
43
+ def _check_for_exception(func: Callable) -> Callable:
44
+ """
45
+ Decorator that checks if an exception has been caught before calling the
46
+ decorated function
47
+ """
48
+
49
+ def wrapped_func(self, *args, **kwargs):
50
+ if not self._has_exception: # Raises if there is an exception # pragma: no branch
51
+ return func(self, *args, **kwargs)
52
+
53
+ return wrapped_func
54
+
55
+
56
+ class NukeAdaptor(Adaptor):
57
+ """
58
+ Adaptor that creates a session in Nuke to Render interactively.
59
+ """
60
+
61
+ _SERVER_START_TIMEOUT_SECONDS = 30
62
+ _SERVER_END_TIMEOUT_SECONDS = 30
63
+ _NUKE_START_TIMEOUT_SECONDS = 300
64
+ _NUKE_END_TIMEOUT_SECONDS = 30
65
+
66
+ _server: AdaptorServer | None = None
67
+ _server_thread: threading.Thread | None = None
68
+ _nuke_client: LoggingSubprocess | None = None
69
+ _action_queue = ActionsQueue()
70
+ _is_rendering: bool = False
71
+ # If a thread raises an exception we will update this to raise in the main thread
72
+ _exc_info: Exception | None = None
73
+ _performing_cleanup = False
74
+ _regex_callbacks: list | None = None
75
+ _validators: AdaptorDataValidators | None = None
76
+ _telemetry_client: TelemetryClient | None = None
77
+
78
+ # Output tracking for progress handling
79
+ _curr_output: int = 1
80
+ _total_outputs: int = 1
81
+ _nuke_version: str = ""
82
+
83
+ @property
84
+ def integration_data_interface_version(self) -> SemanticVersion:
85
+ return SemanticVersion(major=0, minor=1)
86
+
87
+ @staticmethod
88
+ def _get_timer(timeout: int | float) -> Callable[[], bool]:
89
+ """Given a timeout length, returns a lambda which returns False until the timeout occurs"""
90
+ timeout_time = time.time() + timeout
91
+ return lambda: time.time() >= timeout_time
92
+
93
+ @property
94
+ def _has_exception(self) -> bool:
95
+ """Property which checks the private _exc_info property for an exception
96
+
97
+ Raises:
98
+ self._exc_info: An exception if there is one
99
+
100
+ Returns:
101
+ bool: False there is no exception waiting to be raised
102
+ """
103
+ if self._exc_info and not self._performing_cleanup:
104
+ raise self._exc_info
105
+ return False
106
+
107
+ @property
108
+ def continue_on_error(self) -> bool:
109
+ """Property which returns whether to continue on errors or not
110
+
111
+ Returns:
112
+ bool: True if the behavior is to continue on errors. False otherwise.
113
+ """
114
+ return cast(bool, self.init_data.get("continue_on_error", True))
115
+
116
+ @property
117
+ def _nuke_is_running(self) -> bool:
118
+ """Property which indicates that the nuke client is running
119
+
120
+ Returns:
121
+ bool: True if the nuke client is running, false otherwise
122
+ """
123
+ return self._nuke_client is not None and self._nuke_client.is_running
124
+
125
+ @property
126
+ def progress(self) -> float:
127
+ """
128
+ Property which calculates progress based on the number of outputs
129
+ reported and the total outputs expected
130
+
131
+ Returns:
132
+ float: The calculated progress
133
+ """
134
+ return max(min(round(100.0 * self._curr_output / self._total_outputs, 2), 100), 0)
135
+
136
+ @property
137
+ def validators(self) -> AdaptorDataValidators:
138
+ if not self._validators:
139
+ cur_dir = os.path.dirname(__file__)
140
+ schema_dir = os.path.join(cur_dir, "schemas")
141
+ self._validators = AdaptorDataValidators.for_adaptor(schema_dir)
142
+ return self._validators
143
+
144
+ @property
145
+ def regex_callbacks(self) -> list[RegexCallback]:
146
+ """
147
+ Returns a list of RegexCallbacks used by the Nuke Adaptor
148
+
149
+ Returns:
150
+ list[RegexCallback]: List of Regex Callbacks to add
151
+ """
152
+ if not self._regex_callbacks:
153
+ callback_list = []
154
+ completed_regexes = [
155
+ re.compile("NukeClient: Finished Rendering Frame [0-9]+"),
156
+ re.compile("NukeClient: Finished Rendering Frames [0-9]+-[0-9]+"),
157
+ ]
158
+ progress_regexes = [
159
+ re.compile(
160
+ "NukeClient: Creating outputs ([0-9]+)-([0-9]+) of ([0-9]+) total outputs."
161
+ ),
162
+ ]
163
+ error_regexes = [
164
+ re.compile(".*ERROR:.*"),
165
+ re.compile(".*Error:.*"),
166
+ re.compile(".*Error :.*"),
167
+ re.compile(".*Eddy\\[ERROR\\].*"),
168
+ ]
169
+ # Capture the major minor group (ie. 15.0), patch version (ie. v1) is an optional subgroup.
170
+ version_regexes = [re.compile("NukeClient: Nuke Version ([0-9]+.[0-9]+)(v[0-9]+)?")]
171
+ output_complete_regexes = [re.compile(r"Writing .+ took [0-9\.]+ seconds")]
172
+ callback_list.append(RegexCallback(completed_regexes, self._handle_complete))
173
+ callback_list.append(RegexCallback(progress_regexes, self._handle_progress))
174
+ callback_list.append(
175
+ RegexCallback(output_complete_regexes, self._handle_output_complete)
176
+ )
177
+ callback_list.append(RegexCallback(error_regexes, self._handle_error))
178
+ callback_list.append(RegexCallback(version_regexes, self._handle_version))
179
+ self._regex_callbacks = callback_list
180
+ return self._regex_callbacks
181
+
182
+ @_check_for_exception
183
+ def _handle_complete(self, match: re.Match) -> None:
184
+ """
185
+ Callback for stdout that indicates completeness of a render. Updates progress to 100
186
+ Args:
187
+ match (re.Match): The match object from the regex pattern that was matched the message
188
+ """
189
+ self._is_rendering = False
190
+ self.update_status(progress=100, status_message="RENDER COMPLETE")
191
+
192
+ @_check_for_exception
193
+ def _handle_progress(self, match: re.Match) -> None:
194
+ """
195
+ Callback for stdout that indicates progress of a render.
196
+ Args:
197
+ match (re.Match): The match object from the regex pattern that was matched the message
198
+ """
199
+ self._curr_output = int(match.groups()[0])
200
+ self._total_outputs = int(match.groups()[2])
201
+ self.update_status(progress=self.progress)
202
+
203
+ @_check_for_exception
204
+ def _handle_output_complete(self, match: re.Match) -> None:
205
+ """
206
+ Callback for stdout that indicates an outpout has been created.
207
+ Args:
208
+ match (re.Match): The match object from the regex pattern that was matched the message
209
+ """
210
+ self._curr_output += 1
211
+ if self._is_rendering:
212
+ self.update_status(progress=self.progress)
213
+
214
+ def _handle_error(self, match: re.Match) -> None:
215
+ """
216
+ Callback for stdout that indicates an error or warning. Sets the private _exc_info variable
217
+ which will be raised in the main thread.
218
+
219
+ Args:
220
+ match (re.Match): The match object from the regex pattern that was matched the message
221
+ """
222
+ if not self.continue_on_error:
223
+ self._exc_info = RuntimeError(f"Nuke Encountered an Error: {match.group(0)}")
224
+
225
+ def _handle_version(self, match: re.Match) -> None:
226
+ """
227
+ Callback for stdout that records the Nuke version.
228
+ Args:
229
+ match (re.Match): The match object from the regex pattern that was matched the message
230
+ """
231
+ self._nuke_version = match.groups()[0]
232
+ if len(match.groups()) > 1 and match.groups()[1]:
233
+ self._nuke_version += match.groups()[1]
234
+
235
+ @property
236
+ def server_server_path(self) -> str:
237
+ """
238
+ Performs a busy wait for the socket path that the adaptor server is running on, then returns
239
+ it.
240
+
241
+ Raises:
242
+ RuntimeError: If the server does not finish initializing
243
+
244
+ Returns:
245
+ str: The socket path the adaptor server is running on.
246
+ """
247
+ is_timed_out = self._get_timer(self._SERVER_START_TIMEOUT_SECONDS)
248
+ while (self._server is None or self._server.server_path is None) and not is_timed_out():
249
+ time.sleep(0.01)
250
+
251
+ if self._server is not None and self._server.server_path is not None:
252
+ return self._server.server_path
253
+
254
+ raise RuntimeError("Could not find a socket because the server did not finish initializing")
255
+
256
+ @property
257
+ def nuke_client_path(self) -> str:
258
+ """
259
+ Obtains the nuke_client.py path by searching directories in sys.path
260
+
261
+ Raises:
262
+ FileNotFoundError: If the nuke_client.py file could not be found.
263
+
264
+ Returns:
265
+ str: The path to the nuke_client.py file.
266
+ """
267
+ for dir_ in sys.path:
268
+ path = os.path.join(dir_, "deadline", "nuke_adaptor", "NukeClient", "nuke_client.py")
269
+ if os.path.isfile(path):
270
+ return path
271
+ raise FileNotFoundError(
272
+ "Could not find nuke_client.py. Check that the NukeClient package is in one of the "
273
+ f"following directories: {sys.path[1:]}"
274
+ )
275
+
276
+ def on_start(self) -> None:
277
+ """
278
+ Initializes Nuke for job stickiness by starting Nuke, establishing IPC, and initializing the
279
+ Nuke environment with the given Nuke script and any other init data.
280
+
281
+ Raises:
282
+ jsonschema.ValidationError: When init_data fails validation against the adaptor schema.
283
+ jsonschema.SchemaError: When the adaptor schema itself is nonvalid.
284
+ RuntimeError: If Nuke did not complete initialization actions due to an exception
285
+ TimeoutError: If Nuke did not complete initialization actions due to timing out.
286
+ FileNotFoundError: If the nuke_client.py file could not be found.
287
+ KeyError: If a configuration for the given platform and version does not exist.
288
+ """
289
+ self.validators.init_data.validate(self.init_data)
290
+
291
+ self.update_status(progress=0, status_message="Initializing Nuke")
292
+ self._server_thread = self._start_nuke_server_thread()
293
+ self._populate_action_queue()
294
+
295
+ self._start_nuke_client()
296
+
297
+ is_timed_out = self._get_timer(self._NUKE_START_TIMEOUT_SECONDS)
298
+ while self._nuke_is_running and not self._has_exception and len(self._action_queue) > 0:
299
+ if is_timed_out():
300
+ raise TimeoutError(
301
+ "Nuke did not complete initialization actions in "
302
+ f"{self._NUKE_START_TIMEOUT_SECONDS} seconds and failed to start."
303
+ )
304
+
305
+ time.sleep(0.1) # busy wait for nuke to finish initialization
306
+
307
+ self._get_deadline_telemetry_client().record_event(
308
+ event_type="com.amazon.rum.deadline.adaptor.runtime.start", event_details={}
309
+ )
310
+
311
+ if len(self._action_queue) > 0:
312
+ raise RuntimeError(
313
+ "Nuke encountered an error and was not able to complete initialization actions."
314
+ )
315
+
316
+ def on_run(self, run_data: dict) -> None:
317
+ """
318
+ This starts a render in Nuke for the given frame and performs a busy wait until the render
319
+ completes.
320
+ """
321
+ if not self._nuke_is_running:
322
+ raise NukeNotRunningError("Cannot render because Nuke is not running.")
323
+
324
+ if "frameRange" not in run_data and "frame" not in run_data:
325
+ raise jsonschema.exceptions.ValidationError(
326
+ "Cannot run Nuke adaptor. 'frame' or 'frameRange' is a required property."
327
+ )
328
+
329
+ self.validators.run_data.validate(run_data)
330
+ self._is_rendering = True
331
+
332
+ self._action_queue.enqueue_action(
333
+ Action(
334
+ "start_render",
335
+ {"frameRange": run_data.get("frameRange", str(run_data.get("frame", "")))},
336
+ )
337
+ )
338
+
339
+ while self._nuke_is_running and self._is_rendering and not self._has_exception:
340
+ time.sleep(0.1) # busy wait so that on_cleanup is not called
341
+
342
+ if not self._nuke_is_running and self._nuke_client: # Nuke Client will always exist here.
343
+ # This is always an error case because the Nuke Client should still be running and
344
+ # waiting for the next command. If the thread finished, then we cannot continue
345
+ exit_code = self._nuke_client.returncode
346
+
347
+ self._get_deadline_telemetry_client().record_error(
348
+ {"exit_code": exit_code, "exception_scope": "on_run"}, str(RuntimeError)
349
+ )
350
+ raise RuntimeError(
351
+ "Nuke exited early and did not render successfully, please check render logs. "
352
+ f"Exit code {exit_code}"
353
+ )
354
+
355
+ def on_stop(self) -> None:
356
+ """
357
+ No action needed but this function must be implemented
358
+ """
359
+ return
360
+
361
+ def on_cleanup(self):
362
+ """
363
+ Cleans up the adaptor by closing the nuke client and adaptor server.
364
+ """
365
+ self._performing_cleanup = True
366
+
367
+ self._action_queue.enqueue_action(Action("close"), front=True)
368
+ is_timed_out = self._get_timer(self._NUKE_END_TIMEOUT_SECONDS)
369
+ while self._nuke_is_running and not is_timed_out():
370
+ time.sleep(0.1)
371
+ if self._nuke_is_running and self._nuke_client:
372
+ _logger.error(
373
+ "Nuke did not complete cleanup actions and failed to gracefully shutdown. "
374
+ "Terminating."
375
+ )
376
+ self._nuke_client.terminate()
377
+
378
+ if self._server:
379
+ self._server.shutdown()
380
+
381
+ if self._server_thread and self._server_thread.is_alive():
382
+ self._server_thread.join(timeout=self._SERVER_END_TIMEOUT_SECONDS)
383
+ if self._server_thread.is_alive():
384
+ _logger.error("Failed to shutdown the Nuke Adaptor server.")
385
+
386
+ self._performing_cleanup = False
387
+
388
+ def on_cancel(self):
389
+ """
390
+ Cancels the current render if Nuke is rendering.
391
+ """
392
+ _logger.info("CANCEL REQUESTED")
393
+ if not self._nuke_client or not self._nuke_is_running:
394
+ _logger.info("Nothing to cancel because Nuke is not running")
395
+ return
396
+
397
+ # Terminate immediately since the Nuke client does not have a graceful shutdown
398
+ self._nuke_client.terminate(grace_time_s=0)
399
+
400
+ def _start_nuke_server_thread(self) -> threading.Thread:
401
+ """
402
+ Starts the nuke adaptor server in a thread.
403
+ Sets the environment variable "NUKE_ADAPTOR_SERVER_PATH" to the socket the server is running
404
+ on after the server has finished starting.
405
+
406
+ Returns:
407
+ threading.Thread: The thread in which the server is running
408
+ """
409
+
410
+ def start_nuke_server() -> None:
411
+ """
412
+ Starts a server with the given ActionsQueue, attaches the server to the adaptor and
413
+ serves forever in a blocking call.
414
+ """
415
+ self._server = AdaptorServer(self._action_queue, self)
416
+ self._server.serve_forever()
417
+
418
+ server_thread = threading.Thread(target=start_nuke_server)
419
+ server_thread.start()
420
+ os.environ["NUKE_ADAPTOR_SERVER_PATH"] = self.server_server_path
421
+
422
+ return server_thread
423
+
424
+ def _start_nuke_client(self) -> None:
425
+ """
426
+ Starts the nuke client by launching Nuke with the nuke_client.py file and the generated
427
+ arguments.
428
+
429
+ Nuke must be on the system PATH, for example due to a Rez environment being active.
430
+
431
+ Raises:
432
+ FileNotFoundError: If the nuke_client.py file could not be found.
433
+ KeyError: If a configuration for the given platform and version does not exist.
434
+ """
435
+ nuke_exe = os.environ.get("NUKE_ADAPTOR_NUKE_EXECUTABLE", "nuke")
436
+ regexhandler = RegexHandler(self.regex_callbacks)
437
+
438
+ # Add the Open Job Description namespace directory to PYTHONPATH, so that adaptor_runtime_client
439
+ # will be available directly to the nuke client.
440
+ import openjd.adaptor_runtime_client
441
+ import deadline.nuke_adaptor
442
+ import deadline.nuke_util
443
+
444
+ openjd_namespace_dir = os.path.dirname(
445
+ os.path.dirname(openjd.adaptor_runtime_client.__file__)
446
+ )
447
+ deadline_adaptor_namespace_dir = os.path.dirname(
448
+ os.path.dirname(deadline.nuke_adaptor.__file__)
449
+ )
450
+ deadline_util_namespace_dir = os.path.dirname(os.path.dirname(deadline.nuke_util.__file__))
451
+ python_path_addition = f"{openjd_namespace_dir}{os.pathsep}{deadline_adaptor_namespace_dir}{os.pathsep}{deadline_util_namespace_dir}"
452
+ if "PYTHONPATH" in os.environ:
453
+ os.environ["PYTHONPATH"] = (
454
+ f"{os.environ['PYTHONPATH']}{os.pathsep}{python_path_addition}"
455
+ )
456
+ else:
457
+ os.environ["PYTHONPATH"] = python_path_addition
458
+
459
+ self._nuke_client = LoggingSubprocess(
460
+ args=[nuke_exe, "-V", "2", "-t", self.nuke_client_path],
461
+ stdout_handler=regexhandler,
462
+ stderr_handler=regexhandler,
463
+ )
464
+
465
+ def _populate_action_queue(self) -> None:
466
+ """
467
+ Populates the adaptor server's action queue with actions from the init_data that the Nuke
468
+ Client will request and perform. The action must be present in the _FIRST_NUKE_ACTIONS or
469
+ _NUKE_INIT_KEYS set to be added to the action queue.
470
+ """
471
+ for name in _FIRST_NUKE_ACTIONS:
472
+ self._action_queue.enqueue_action(Action(name, {name: self.init_data[name]}))
473
+
474
+ for name in _NUKE_INIT_KEYS:
475
+ if name in self.init_data:
476
+ self._action_queue.enqueue_action(Action(name, {name: self.init_data[name]}))
477
+
478
+ def _get_deadline_telemetry_client(self):
479
+ """
480
+ Wrapper around the Deadline Client Library telemetry client, in order to set package-specific information
481
+ """
482
+ if not self._telemetry_client:
483
+ self._telemetry_client = get_deadline_cloud_library_telemetry_client()
484
+ self._telemetry_client.update_common_details(
485
+ {
486
+ "deadline-cloud-for-nuke-adaptor-version": adaptor_version,
487
+ "nuke-version": self._nuke_version,
488
+ "open-jd-adaptor-runtime-version": openjd_adaptor_version,
489
+ }
490
+ )
491
+ return self._telemetry_client
@@ -0,0 +1 @@
1
+ # Marker file that indicates this package supports typing
@@ -0,0 +1,25 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "properties": {
5
+ "continue_on_error": {"type": "boolean"},
6
+ "proxy": {"type": "boolean"},
7
+ "write_nodes": {
8
+ "type": "array",
9
+ "items": {
10
+ "type": "string"
11
+ }
12
+ },
13
+ "views": {
14
+ "type": "array",
15
+ "items": {
16
+ "type": "string"
17
+ }
18
+ },
19
+ "telemetry_opt_out": { "type" : "boolean" },
20
+ "script_file": { "type": "string" }
21
+ },
22
+ "required": [
23
+ "script_file"
24
+ ]
25
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "properties": {
5
+ "frame": {"type": "number"},
6
+ "frameRange": { "type": "string"}
7
+ },
8
+ "optional": ["frameRange", "frame"]
9
+ }
@@ -0,0 +1,6 @@
1
+ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+
3
+ from .nuke_client import NukeClient
4
+ from .nuke_handler import NukeHandler
5
+
6
+ __all__ = ["NukeClient", "NukeHandler"]