sg-python-api 0.1.2__py3-none-any.whl → 0.2.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.
- {sg_python_api-0.1.2.dist-info → sg_python_api-0.2.0.dist-info}/METADATA +21 -24
- sg_python_api-0.2.0.dist-info/RECORD +58 -0
- shotgun_api3/__init__.py +4 -0
- shotgun_api3/_async_client.py +347 -281
- shotgun_api3/_async_driver.py +25 -55
- shotgun_api3/_async_httpx2.py +92 -59
- shotgun_api3/_async_transport.py +38 -3
- shotgun_api3/_capabilities.py +4 -3
- shotgun_api3/_client.py +296 -422
- shotgun_api3/_config.py +245 -120
- shotgun_api3/_connections.py +144 -0
- shotgun_api3/_crud.py +25 -250
- shotgun_api3/_driver.py +29 -54
- shotgun_api3/_execution.py +1 -3
- shotgun_api3/_files.py +193 -21
- shotgun_api3/_methods.py +59 -411
- shotgun_api3/_protocol.py +27 -53
- shotgun_api3/_transport.py +82 -407
- shotgun_api3/_version.py +7 -2
- shotgun_api3/lib/mockgun/__init__.py +20 -7
- shotgun_api3/lib/mockgun/_activity.py +510 -0
- shotgun_api3/lib/mockgun/_async_client.py +196 -0
- shotgun_api3/lib/mockgun/_dates.py +164 -0
- shotgun_api3/lib/mockgun/_errors.py +18 -0
- shotgun_api3/lib/mockgun/_events.py +1031 -0
- shotgun_api3/lib/mockgun/_follows.py +217 -0
- shotgun_api3/lib/mockgun/_handlers.py +558 -0
- shotgun_api3/lib/mockgun/_links.py +440 -0
- shotgun_api3/lib/mockgun/_new_client.py +92 -0
- shotgun_api3/lib/mockgun/_presets.py +492 -0
- shotgun_api3/lib/mockgun/_query.py +2163 -0
- shotgun_api3/lib/mockgun/_retirement.py +368 -0
- shotgun_api3/lib/mockgun/_schema.py +172 -0
- shotgun_api3/lib/mockgun/_schema_writes.py +425 -0
- shotgun_api3/lib/mockgun/_search.py +378 -0
- shotgun_api3/lib/mockgun/_server.py +169 -0
- shotgun_api3/lib/mockgun/_sessions.py +206 -0
- shotgun_api3/lib/mockgun/_site.py +150 -0
- shotgun_api3/lib/mockgun/_site_data.py +584 -0
- shotgun_api3/lib/mockgun/_storage.py +208 -0
- shotgun_api3/lib/mockgun/_store.py +1446 -0
- shotgun_api3/lib/mockgun/_summaries.py +964 -0
- shotgun_api3/lib/mockgun/_sync_client.py +190 -0
- shotgun_api3/lib/mockgun/_threads.py +226 -0
- shotgun_api3/lib/mockgun/_thumbnails.py +146 -0
- shotgun_api3/lib/mockgun/_transport.py +145 -0
- shotgun_api3/lib/mockgun/_uploads.py +417 -0
- shotgun_api3/lib/mockgun/_wire.py +120 -0
- shotgun_api3/lib/mockgun/mockgun.py +14 -0
- shotgun_api3/lib/sgtimezone.py +24 -1
- sg_python_api-0.1.2.dist-info/RECORD +0 -31
- shotgun_api3/_signatures.py +0 -53
- shotgun_api3/lib/mockgun/_async.py +0 -315
- shotgun_api3/lib/mockgun/_mockgun.py +0 -1666
- {sg_python_api-0.1.2.dist-info → sg_python_api-0.2.0.dist-info}/WHEEL +0 -0
- {sg_python_api-0.1.2.dist-info → sg_python_api-0.2.0.dist-info}/licenses/LICENSE +0 -0
shotgun_api3/_client.py
CHANGED
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
import copy
|
|
4
4
|
import dataclasses
|
|
5
5
|
import datetime as _dt_module
|
|
6
|
-
import inspect
|
|
7
6
|
import os
|
|
8
7
|
import threading
|
|
9
8
|
import urllib.request
|
|
10
|
-
import uuid
|
|
11
9
|
from collections.abc import Callable, Generator, Iterator, Mapping
|
|
12
10
|
from contextlib import ExitStack, contextmanager, suppress
|
|
11
|
+
from functools import partial
|
|
13
12
|
from pathlib import Path
|
|
14
13
|
from typing import (
|
|
15
14
|
Any,
|
|
15
|
+
ClassVar,
|
|
16
16
|
Literal,
|
|
17
17
|
Never,
|
|
18
18
|
TypeAlias,
|
|
@@ -48,7 +48,6 @@ from ._execution import (
|
|
|
48
48
|
release_lease,
|
|
49
49
|
retire_transport,
|
|
50
50
|
)
|
|
51
|
-
from ._signatures import bind_arguments, expose_signature
|
|
52
51
|
from ._transport import (
|
|
53
52
|
SendError,
|
|
54
53
|
StreamingResponse,
|
|
@@ -58,152 +57,12 @@ from ._transport import (
|
|
|
58
57
|
TransportResponse,
|
|
59
58
|
Urllib3Transport,
|
|
60
59
|
)
|
|
61
|
-
from ._version import
|
|
60
|
+
from ._version import COMPATIBILITY_VERSION
|
|
62
61
|
|
|
63
62
|
_ReadinessKey: TypeAlias = tuple[str, int]
|
|
64
63
|
_UploadResult = TypeVar('_UploadResult')
|
|
65
64
|
|
|
66
|
-
__version__ =
|
|
67
|
-
|
|
68
|
-
_CONSTRUCTOR_PARAMETERS = (
|
|
69
|
-
inspect.Parameter('base_url', inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=str),
|
|
70
|
-
inspect.Parameter(
|
|
71
|
-
'script_name',
|
|
72
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
73
|
-
default=None,
|
|
74
|
-
annotation=str | None,
|
|
75
|
-
),
|
|
76
|
-
inspect.Parameter(
|
|
77
|
-
'api_key',
|
|
78
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
79
|
-
default=None,
|
|
80
|
-
annotation=str | None,
|
|
81
|
-
),
|
|
82
|
-
inspect.Parameter(
|
|
83
|
-
'convert_datetimes_to_utc',
|
|
84
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
85
|
-
default=True,
|
|
86
|
-
annotation=bool,
|
|
87
|
-
),
|
|
88
|
-
inspect.Parameter(
|
|
89
|
-
'http_proxy',
|
|
90
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
91
|
-
default=None,
|
|
92
|
-
annotation=str | None,
|
|
93
|
-
),
|
|
94
|
-
inspect.Parameter(
|
|
95
|
-
'connect',
|
|
96
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
97
|
-
default=True,
|
|
98
|
-
annotation=bool,
|
|
99
|
-
),
|
|
100
|
-
inspect.Parameter(
|
|
101
|
-
'ca_certs',
|
|
102
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
103
|
-
default=None,
|
|
104
|
-
annotation=str | None,
|
|
105
|
-
),
|
|
106
|
-
inspect.Parameter(
|
|
107
|
-
'login',
|
|
108
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
109
|
-
default=None,
|
|
110
|
-
annotation=str | None,
|
|
111
|
-
),
|
|
112
|
-
inspect.Parameter(
|
|
113
|
-
'password',
|
|
114
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
115
|
-
default=None,
|
|
116
|
-
annotation=str | None,
|
|
117
|
-
),
|
|
118
|
-
inspect.Parameter(
|
|
119
|
-
'sudo_as_login',
|
|
120
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
121
|
-
default=None,
|
|
122
|
-
annotation=str | None,
|
|
123
|
-
),
|
|
124
|
-
inspect.Parameter(
|
|
125
|
-
'session_token',
|
|
126
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
127
|
-
default=None,
|
|
128
|
-
annotation=str | None,
|
|
129
|
-
),
|
|
130
|
-
inspect.Parameter(
|
|
131
|
-
'auth_token',
|
|
132
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
133
|
-
default=None,
|
|
134
|
-
annotation=str | None,
|
|
135
|
-
),
|
|
136
|
-
)
|
|
137
|
-
_UPLOAD_DOCSTRING = """Upload a file or thumbnail and return its Attachment ID.
|
|
138
|
-
|
|
139
|
-
A server requiring legacy form uploads raises `ShotgunError` before
|
|
140
|
-
any upload request is sent. Server capability reads may occur.
|
|
141
|
-
|
|
142
|
-
Args:
|
|
143
|
-
entity_type: Entity type receiving the upload.
|
|
144
|
-
entity_id: Numeric identifier of the receiving entity.
|
|
145
|
-
path: Existing non-empty file path as text or filesystem-encoded bytes.
|
|
146
|
-
field_name: Optional file field receiving an Attachment.
|
|
147
|
-
display_name: Optional Attachment display name.
|
|
148
|
-
tag_list: Optional comma-delimited Attachment tags.
|
|
149
|
-
created_at: Optional Attachment creation timestamp.
|
|
150
|
-
|
|
151
|
-
Returns:
|
|
152
|
-
Created Attachment ID.
|
|
153
|
-
|
|
154
|
-
Raises:
|
|
155
|
-
TypeError: If arguments do not match the documented signature.
|
|
156
|
-
ShotgunError: If the file or an upload response is invalid, an RPC
|
|
157
|
-
fault or terminal transport failure occurs, or the server
|
|
158
|
-
requires legacy form uploads.
|
|
159
|
-
ProtocolError: If an upload endpoint returns an HTTP error.
|
|
160
|
-
ValueError: If authenticated HTTP violates the configured origin policy.
|
|
161
|
-
"""
|
|
162
|
-
_UPLOAD_PARAMETERS = (
|
|
163
|
-
inspect.Parameter('entity_type', inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=str),
|
|
164
|
-
inspect.Parameter('entity_id', inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=int),
|
|
165
|
-
inspect.Parameter('path', inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=str | bytes),
|
|
166
|
-
inspect.Parameter(
|
|
167
|
-
'field_name',
|
|
168
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
169
|
-
default=None,
|
|
170
|
-
annotation=str | None,
|
|
171
|
-
),
|
|
172
|
-
inspect.Parameter(
|
|
173
|
-
'display_name',
|
|
174
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
175
|
-
default=None,
|
|
176
|
-
annotation=str | None,
|
|
177
|
-
),
|
|
178
|
-
inspect.Parameter(
|
|
179
|
-
'tag_list',
|
|
180
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
181
|
-
default=None,
|
|
182
|
-
annotation=str | None,
|
|
183
|
-
),
|
|
184
|
-
inspect.Parameter(
|
|
185
|
-
'created_at',
|
|
186
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
187
|
-
default=None,
|
|
188
|
-
annotation=_dt_module.datetime | None,
|
|
189
|
-
),
|
|
190
|
-
)
|
|
191
|
-
CONSTRUCTOR_SIGNATURE = inspect.Signature(_CONSTRUCTOR_PARAMETERS, return_annotation=None)
|
|
192
|
-
_METHOD_CONSTRUCTOR_SIGNATURE = inspect.Signature(
|
|
193
|
-
(
|
|
194
|
-
inspect.Parameter('self', inspect.Parameter.POSITIONAL_OR_KEYWORD),
|
|
195
|
-
*_CONSTRUCTOR_PARAMETERS,
|
|
196
|
-
),
|
|
197
|
-
return_annotation=None,
|
|
198
|
-
)
|
|
199
|
-
_METHOD_UPLOAD_SIGNATURE = inspect.Signature(
|
|
200
|
-
(
|
|
201
|
-
inspect.Parameter('self', inspect.Parameter.POSITIONAL_OR_KEYWORD),
|
|
202
|
-
*_UPLOAD_PARAMETERS,
|
|
203
|
-
),
|
|
204
|
-
return_annotation=int,
|
|
205
|
-
)
|
|
206
|
-
_UPLOAD_SIGNATURE = inspect.Signature(_UPLOAD_PARAMETERS, return_annotation=int)
|
|
65
|
+
__version__ = COMPATIBILITY_VERSION
|
|
207
66
|
|
|
208
67
|
|
|
209
68
|
@dataclasses.dataclass(frozen=True)
|
|
@@ -272,13 +131,16 @@ class _DownloadExchange:
|
|
|
272
131
|
transfer = ExceptionCapture()
|
|
273
132
|
try:
|
|
274
133
|
with transfer:
|
|
275
|
-
|
|
134
|
+
with _files.download_destination_io(destination):
|
|
135
|
+
handle = stack.enter_context(_files.download_temporary(destination))
|
|
276
136
|
temporary = Path(handle.name)
|
|
277
137
|
control.consume_into(
|
|
278
138
|
chunks,
|
|
279
|
-
|
|
139
|
+
partial(_files.write_download_chunk, destination, handle),
|
|
280
140
|
total_bytes=total_bytes,
|
|
281
141
|
)
|
|
142
|
+
with _files.download_destination_io(destination):
|
|
143
|
+
handle.flush()
|
|
282
144
|
opened_stack = stack
|
|
283
145
|
stack = None
|
|
284
146
|
opened_cleanup = SuppressedExceptionCapture()
|
|
@@ -288,7 +150,8 @@ class _DownloadExchange:
|
|
|
288
150
|
raise _DownloadCleanupError from None
|
|
289
151
|
if opened_cleanup.exception is not None:
|
|
290
152
|
raise opened_cleanup.exception
|
|
291
|
-
|
|
153
|
+
with _files.download_destination_io(destination):
|
|
154
|
+
temporary.replace(destination)
|
|
292
155
|
finally:
|
|
293
156
|
close_cleanup = SuppressedExceptionCapture()
|
|
294
157
|
unlink_cleanup = SuppressedExceptionCapture()
|
|
@@ -317,12 +180,23 @@ class _DownloadExchange:
|
|
|
317
180
|
return control.consume(chunks, total_bytes=total_bytes)
|
|
318
181
|
return self._write_file(chunks, control, total_bytes)
|
|
319
182
|
|
|
320
|
-
def
|
|
183
|
+
def execute(
|
|
321
184
|
self,
|
|
322
185
|
driver: Driver,
|
|
323
186
|
operation: _protocol.OperationDescriptor,
|
|
324
187
|
) -> bytes | str:
|
|
325
|
-
"""Execute the workflow through the common streaming attempt loop.
|
|
188
|
+
"""Execute the workflow through the common streaming attempt loop.
|
|
189
|
+
|
|
190
|
+
Returns:
|
|
191
|
+
Downloaded bytes, or the destination path for a file download.
|
|
192
|
+
|
|
193
|
+
Raises:
|
|
194
|
+
SendError: If required download cleanup fails.
|
|
195
|
+
TransportError: If the attempt loop cannot complete the transfer.
|
|
196
|
+
ShotgunFileDownloadError: If the response or redirect is invalid,
|
|
197
|
+
or creating, writing, flushing, or publishing the destination
|
|
198
|
+
file fails.
|
|
199
|
+
"""
|
|
326
200
|
try:
|
|
327
201
|
return driver.execute(
|
|
328
202
|
operation,
|
|
@@ -349,16 +223,6 @@ class _InvocationOptions:
|
|
|
349
223
|
auth_spec: _protocol.AuthSpec | None = None
|
|
350
224
|
|
|
351
225
|
|
|
352
|
-
def _bind_upload(
|
|
353
|
-
args: tuple[object, ...],
|
|
354
|
-
kwargs: dict[str, object],
|
|
355
|
-
) -> _files.UploadArguments:
|
|
356
|
-
"""Bind runtime arguments with upload-specific errors."""
|
|
357
|
-
bound = bind_arguments(_UPLOAD_SIGNATURE, args, kwargs, 'Shotgun.upload()')
|
|
358
|
-
arguments = cast('Callable[..., _files.UploadArguments]', _files.UploadArguments)
|
|
359
|
-
return arguments(**bound.arguments)
|
|
360
|
-
|
|
361
|
-
|
|
362
226
|
def _execute_upload_exchange(
|
|
363
227
|
driver: Driver,
|
|
364
228
|
context: RequestContext,
|
|
@@ -374,7 +238,6 @@ def _execute_upload_exchange(
|
|
|
374
238
|
headers=dict(exchange.headers),
|
|
375
239
|
body=exchange.body_factory(),
|
|
376
240
|
timeout=context.timeout,
|
|
377
|
-
token=uuid.uuid4().hex,
|
|
378
241
|
)
|
|
379
242
|
|
|
380
243
|
def consume(
|
|
@@ -400,43 +263,23 @@ def _execute_upload_exchange(
|
|
|
400
263
|
)
|
|
401
264
|
|
|
402
265
|
|
|
403
|
-
def
|
|
404
|
-
"""
|
|
405
|
-
return expose_signature(function, _METHOD_UPLOAD_SIGNATURE, _UPLOAD_DOCSTRING)
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
def bind_constructor(
|
|
409
|
-
args: tuple[object, ...],
|
|
410
|
-
kwargs: dict[str, object],
|
|
411
|
-
client_name: str,
|
|
412
|
-
) -> ConstructorOptions:
|
|
413
|
-
"""Bind constructor arguments with client-specific errors.
|
|
266
|
+
def build_config(options: ConstructorOptions, *, in_process: bool = False) -> Config:
|
|
267
|
+
"""Initialize and validate network-free configuration, auth, and proxy fields.
|
|
414
268
|
|
|
415
269
|
Args:
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
270
|
+
options: Constructor values for the site, authentication, and proxy.
|
|
271
|
+
in_process: Whether requests stay inside this process, allowing
|
|
272
|
+
authentication without the network HTTP origin restriction.
|
|
419
273
|
|
|
420
274
|
Returns:
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
Raises:
|
|
424
|
-
TypeError: If the arguments do not match the public signature.
|
|
425
|
-
"""
|
|
426
|
-
bound = bind_arguments(CONSTRUCTOR_SIGNATURE, args, kwargs, f'{client_name}.__init__()')
|
|
427
|
-
constructor = cast('Callable[..., ConstructorOptions]', ConstructorOptions)
|
|
428
|
-
return constructor(**bound.arguments)
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
def build_config(options: ConstructorOptions) -> Config:
|
|
432
|
-
"""Initialize and validate network-free configuration, auth, and proxy fields.
|
|
275
|
+
A new configuration containing the validated constructor settings.
|
|
433
276
|
|
|
434
277
|
Raises:
|
|
435
278
|
TypeError: If a configuration or proxy value has an unsupported type.
|
|
436
279
|
ValueError: If authentication, site or proxy values, or
|
|
437
280
|
`SHOTGUN_API_RETRY_INTERVAL` are invalid.
|
|
438
281
|
"""
|
|
439
|
-
config = Config()
|
|
282
|
+
config = Config(_in_process=in_process)
|
|
440
283
|
config.set_server_params(options.base_url)
|
|
441
284
|
config.update_fields(
|
|
442
285
|
api_key=options.api_key,
|
|
@@ -455,26 +298,6 @@ def build_config(options: ConstructorOptions) -> Config:
|
|
|
455
298
|
return config
|
|
456
299
|
|
|
457
300
|
|
|
458
|
-
def expose_constructor_signature(function: Callable[..., object]) -> Callable[..., object]:
|
|
459
|
-
"""Expose the documented constructor signature.
|
|
460
|
-
|
|
461
|
-
Args:
|
|
462
|
-
function: Variadic constructor implementation.
|
|
463
|
-
|
|
464
|
-
Returns:
|
|
465
|
-
The same function with its public runtime signature attached.
|
|
466
|
-
"""
|
|
467
|
-
expose_signature(function, _METHOD_CONSTRUCTOR_SIGNATURE, None)
|
|
468
|
-
annotations = {
|
|
469
|
-
name: parameter.annotation
|
|
470
|
-
for name, parameter in CONSTRUCTOR_SIGNATURE.parameters.items()
|
|
471
|
-
if parameter.annotation is not inspect.Parameter.empty
|
|
472
|
-
}
|
|
473
|
-
annotations['return'] = CONSTRUCTOR_SIGNATURE.return_annotation
|
|
474
|
-
object.__setattr__(function, '__annotations__', annotations)
|
|
475
|
-
return function
|
|
476
|
-
|
|
477
|
-
|
|
478
301
|
class Shotgun:
|
|
479
302
|
"""Provide the synchronous Flow Production Tracking API client surface.
|
|
480
303
|
|
|
@@ -488,14 +311,12 @@ class Shotgun:
|
|
|
488
311
|
config: The writable client configuration.
|
|
489
312
|
server_caps: Validated capabilities for the configured origin.
|
|
490
313
|
server_info: Raw validated server metadata.
|
|
314
|
+
transport: Current transport backend, or `None` before connection or
|
|
315
|
+
after retirement.
|
|
491
316
|
"""
|
|
492
317
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
@overload
|
|
496
|
-
def __init__(self, base_url: Never) -> None: ...
|
|
318
|
+
_in_process: ClassVar[bool] = False
|
|
497
319
|
|
|
498
|
-
@overload
|
|
499
320
|
def __init__(
|
|
500
321
|
self,
|
|
501
322
|
base_url: str,
|
|
@@ -510,10 +331,7 @@ class Shotgun:
|
|
|
510
331
|
sudo_as_login: str | None = None,
|
|
511
332
|
session_token: str | None = None,
|
|
512
333
|
auth_token: str | None = None,
|
|
513
|
-
) -> None:
|
|
514
|
-
|
|
515
|
-
@expose_constructor_signature
|
|
516
|
-
def __init__(self, *args: object, **kwargs: object) -> None:
|
|
334
|
+
) -> None:
|
|
517
335
|
"""Initialize a client for one site and authentication mode.
|
|
518
336
|
|
|
519
337
|
Supply exactly one authentication mode: `script_name` with `api_key`,
|
|
@@ -525,30 +343,60 @@ class Shotgun:
|
|
|
525
343
|
`http_proxy` accepts `[user:pass@]host[:port]`, with port 8080 when
|
|
526
344
|
omitted. A truthy `ca_certs` selects a CA bundle; otherwise
|
|
527
345
|
`SHOTGUN_API_CACERTS` is consulted before using system trust roots.
|
|
346
|
+
`SHOTGUN_API_RETRY_INTERVAL` supplies a nonnegative integer retry
|
|
347
|
+
interval in milliseconds, defaulting to 3000.
|
|
528
348
|
|
|
529
349
|
Construction performs server-readiness I/O by default. Supplying
|
|
530
350
|
`auth_token` also performs a session-token exchange during
|
|
531
351
|
construction, even when `connect` is `False`.
|
|
532
352
|
|
|
533
353
|
Args:
|
|
534
|
-
|
|
535
|
-
|
|
354
|
+
base_url: Flow Production Tracking site URL.
|
|
355
|
+
script_name: Script name for script authentication.
|
|
356
|
+
api_key: API key for script authentication.
|
|
357
|
+
convert_datetimes_to_utc: Whether to convert datetime values to
|
|
358
|
+
UTC.
|
|
359
|
+
http_proxy: Optional proxy authority in `[user:pass@]host[:port]`
|
|
360
|
+
form.
|
|
361
|
+
connect: Whether to perform eager readiness during construction.
|
|
362
|
+
ca_certs: Optional certificate-authority bundle path.
|
|
363
|
+
login: Login for human-user authentication.
|
|
364
|
+
password: Password for human-user authentication.
|
|
365
|
+
sudo_as_login: Optional user login for sudo impersonation.
|
|
366
|
+
session_token: Existing session token for authentication.
|
|
367
|
+
auth_token: Optional two-factor authentication token.
|
|
536
368
|
|
|
537
369
|
Raises:
|
|
538
|
-
|
|
539
|
-
|
|
370
|
+
ValueError: If authentication, URL, or proxy values are invalid,
|
|
371
|
+
the configured CA bundle is not a readable file, or
|
|
372
|
+
`SHOTGUN_API_RETRY_INTERVAL` is not a nonnegative integer.
|
|
540
373
|
ShotgunError: If authentication, server metadata, or an RPC result
|
|
541
374
|
is invalid, or a transport attempt fails.
|
|
542
375
|
ProtocolError: If eager readiness or token exchange receives an
|
|
543
376
|
HTTP error.
|
|
544
377
|
"""
|
|
545
|
-
self._initialize(
|
|
378
|
+
self._initialize(
|
|
379
|
+
ConstructorOptions(
|
|
380
|
+
base_url,
|
|
381
|
+
script_name,
|
|
382
|
+
api_key,
|
|
383
|
+
convert_datetimes_to_utc,
|
|
384
|
+
http_proxy,
|
|
385
|
+
connect,
|
|
386
|
+
ca_certs,
|
|
387
|
+
login,
|
|
388
|
+
password,
|
|
389
|
+
sudo_as_login,
|
|
390
|
+
session_token,
|
|
391
|
+
auth_token,
|
|
392
|
+
)
|
|
393
|
+
)
|
|
546
394
|
|
|
547
395
|
@property
|
|
548
396
|
def _connection(self) -> Transport | None:
|
|
549
397
|
"""Return the current private connection compatibility view."""
|
|
550
398
|
with self._transport_lock:
|
|
551
|
-
return self.
|
|
399
|
+
return self.transport
|
|
552
400
|
|
|
553
401
|
def _invoke(
|
|
554
402
|
self,
|
|
@@ -571,12 +419,16 @@ class Shotgun:
|
|
|
571
419
|
return _protocol.transform_inbound(result, context.convert_datetimes_to_utc)
|
|
572
420
|
|
|
573
421
|
def _new_transport(self, context: RequestContext) -> Transport:
|
|
574
|
-
"""Create a transport for one
|
|
422
|
+
"""Create a transport for one generation; mockgun overrides this package-internal hook."""
|
|
423
|
+
if context.in_process:
|
|
424
|
+
raise RuntimeError('an in-process client must supply its own transport')
|
|
575
425
|
return Urllib3Transport(
|
|
576
426
|
ca_certs=self._ca_certs,
|
|
577
427
|
proxy_headers=dict(context.proxy_headers) or None,
|
|
578
428
|
proxy_url=context.proxy_url,
|
|
579
429
|
pool_maxsize=context.pool_maxsize,
|
|
430
|
+
max_connection_idle_secs=context.max_connection_idle_secs,
|
|
431
|
+
tcp_keepalive_timeout_secs=context.tcp_keepalive_timeout_secs,
|
|
580
432
|
)
|
|
581
433
|
|
|
582
434
|
def _publish_capabilities(
|
|
@@ -614,34 +466,39 @@ class Shotgun:
|
|
|
614
466
|
"""Lease the driver and transport for one complete logical operation."""
|
|
615
467
|
close_after_unlock: list[Transport] = []
|
|
616
468
|
with self._transport_lock:
|
|
617
|
-
|
|
469
|
+
decision = _files.choose_driver_lease(
|
|
470
|
+
self._known_transport,
|
|
471
|
+
self.transport,
|
|
472
|
+
self._driver_generation,
|
|
473
|
+
context.transport_generation,
|
|
474
|
+
self._transport_owned,
|
|
475
|
+
)
|
|
476
|
+
if decision.known_changed:
|
|
618
477
|
if self._known_transport is not None:
|
|
619
478
|
retired = retire_transport(
|
|
620
479
|
self._lease_counts, self._retired_transports, self._known_transport
|
|
621
480
|
)
|
|
622
481
|
if retired is not None:
|
|
623
482
|
close_after_unlock.append(retired)
|
|
624
|
-
self._known_transport = self.
|
|
483
|
+
self._known_transport = self.transport
|
|
625
484
|
self._driver = None
|
|
626
485
|
self._driver_generation = None
|
|
627
486
|
self._transport_owned = False
|
|
628
487
|
|
|
629
|
-
transport = self.
|
|
488
|
+
transport = self.transport
|
|
630
489
|
if transport is None:
|
|
631
490
|
transport = self._new_transport(context)
|
|
632
|
-
self.
|
|
491
|
+
self.transport = transport
|
|
633
492
|
self._known_transport = transport
|
|
634
493
|
self._transport_owned = True
|
|
635
|
-
elif
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
self._transport = transport
|
|
644
|
-
self._known_transport = transport
|
|
494
|
+
elif decision.replace_owned_transport:
|
|
495
|
+
retired = retire_transport(self._lease_counts, self._retired_transports, transport)
|
|
496
|
+
if retired is not None:
|
|
497
|
+
close_after_unlock.append(retired)
|
|
498
|
+
transport = self._new_transport(context)
|
|
499
|
+
self.transport = transport
|
|
500
|
+
self._known_transport = transport
|
|
501
|
+
if decision.reset_driver:
|
|
645
502
|
self._driver = None
|
|
646
503
|
|
|
647
504
|
if self._driver is None:
|
|
@@ -799,7 +656,9 @@ class Shotgun:
|
|
|
799
656
|
_files.SHARE_THUMBNAIL,
|
|
800
657
|
fields,
|
|
801
658
|
),
|
|
802
|
-
lambda text, _headers: _files.parse_link_completion(
|
|
659
|
+
lambda text, _headers: _files.parse_link_completion(
|
|
660
|
+
text, operation='share_thumbnail', entities=entities
|
|
661
|
+
),
|
|
803
662
|
)
|
|
804
663
|
|
|
805
664
|
def _thumbnail_source_ready(
|
|
@@ -873,7 +732,7 @@ class Shotgun:
|
|
|
873
732
|
_files.StorageRange(
|
|
874
733
|
length=prepared.file_size,
|
|
875
734
|
offset=0,
|
|
876
|
-
path=prepared.
|
|
735
|
+
path=prepared.path,
|
|
877
736
|
),
|
|
878
737
|
),
|
|
879
738
|
lambda _text, _headers: None,
|
|
@@ -904,7 +763,16 @@ class Shotgun:
|
|
|
904
763
|
_files.LINK_FILE,
|
|
905
764
|
fields,
|
|
906
765
|
),
|
|
907
|
-
lambda text, _headers: _files.parse_link_completion(
|
|
766
|
+
lambda text, _headers: _files.parse_link_completion(
|
|
767
|
+
text,
|
|
768
|
+
operation='upload link',
|
|
769
|
+
entities=[
|
|
770
|
+
{
|
|
771
|
+
'type': prepared.options.arguments.entity_type,
|
|
772
|
+
'id': prepared.options.arguments.entity_id,
|
|
773
|
+
}
|
|
774
|
+
],
|
|
775
|
+
),
|
|
908
776
|
)
|
|
909
777
|
|
|
910
778
|
@staticmethod
|
|
@@ -973,16 +841,8 @@ class Shotgun:
|
|
|
973
841
|
prepared: _files.PreparedUpload,
|
|
974
842
|
) -> int:
|
|
975
843
|
"""Execute one prepared upload through a captured driver lease."""
|
|
976
|
-
arguments = prepared.options.arguments
|
|
977
844
|
capabilities = self._ensure_readiness(context, driver)
|
|
978
|
-
upload_path = _files.
|
|
979
|
-
_files.choose_upload_path(
|
|
980
|
-
capabilities.server_info,
|
|
981
|
-
arguments.entity_type,
|
|
982
|
-
arguments.field_name,
|
|
983
|
-
prepared.file_size,
|
|
984
|
-
)
|
|
985
|
-
)
|
|
845
|
+
upload_path = _files.choose_prepared_upload_path(capabilities.server_info, prepared)
|
|
986
846
|
multipart = upload_path == 'multipart'
|
|
987
847
|
upload_info = self._upload_allocation(driver, context, prepared, multipart)
|
|
988
848
|
if multipart:
|
|
@@ -1007,14 +867,8 @@ class Shotgun:
|
|
|
1007
867
|
) -> int:
|
|
1008
868
|
"""Execute the exact direct-storage thumbnail workflow."""
|
|
1009
869
|
capabilities = self._ensure_readiness(context, driver)
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
_files.choose_upload_path(
|
|
1013
|
-
capabilities.server_info,
|
|
1014
|
-
arguments.entity_type,
|
|
1015
|
-
arguments.field_name,
|
|
1016
|
-
prepared.file_size,
|
|
1017
|
-
)
|
|
870
|
+
_files.choose_prepared_upload_path(
|
|
871
|
+
capabilities.server_info, prepared, sharing_thumbnail=True
|
|
1018
872
|
)
|
|
1019
873
|
upload_info = self._upload_allocation(driver, context, prepared, multipart=False)
|
|
1020
874
|
self._upload_direct(driver, context, prepared, upload_info)
|
|
@@ -1042,10 +896,6 @@ class Shotgun:
|
|
|
1042
896
|
result.update({field_name: current.get(field_name) for field_name in thumbnails})
|
|
1043
897
|
return result
|
|
1044
898
|
|
|
1045
|
-
@overload
|
|
1046
|
-
def activity_stream_read(self, entity_type: Never) -> dict[str, object]: ...
|
|
1047
|
-
|
|
1048
|
-
@overload
|
|
1049
899
|
def activity_stream_read(
|
|
1050
900
|
self,
|
|
1051
901
|
entity_type: str,
|
|
@@ -1054,30 +904,30 @@ class Shotgun:
|
|
|
1054
904
|
min_id: int | None = None,
|
|
1055
905
|
max_id: int | None = None,
|
|
1056
906
|
limit: int | None = None,
|
|
1057
|
-
) -> dict[str, object]:
|
|
1058
|
-
|
|
1059
|
-
@_methods.expose_activity_stream_read_signature
|
|
1060
|
-
def activity_stream_read(self, *args: object, **kwargs: object) -> dict[str, object]:
|
|
907
|
+
) -> dict[str, object]:
|
|
1061
908
|
"""Read the activity stream for one entity.
|
|
1062
909
|
|
|
1063
910
|
Args:
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
911
|
+
entity_type: Entity type whose activity stream to read.
|
|
912
|
+
entity_id: Numeric identifier of the entity.
|
|
913
|
+
entity_fields: Optional fields to return for linked entity types.
|
|
914
|
+
min_id: Optional minimum activity identifier.
|
|
915
|
+
max_id: Optional maximum activity identifier.
|
|
916
|
+
limit: Optional maximum number of activity records.
|
|
1068
917
|
|
|
1069
918
|
Returns:
|
|
1070
919
|
Activity stream data returned by the server.
|
|
1071
920
|
|
|
1072
921
|
Raises:
|
|
1073
|
-
TypeError: If arguments do not match the documented signature.
|
|
1074
922
|
ShotgunError: If an RPC fault or terminal transport failure occurs,
|
|
1075
923
|
or if the server result has the wrong type.
|
|
1076
924
|
ProtocolError: If a server request returns an HTTP error.
|
|
1077
925
|
ValueError: If authenticated HTTP violates the configured origin
|
|
1078
926
|
policy.
|
|
1079
927
|
"""
|
|
1080
|
-
options = _methods.
|
|
928
|
+
options = _methods.ActivityStreamReadOptions(
|
|
929
|
+
entity_type, entity_id, entity_fields, min_id, max_id, limit
|
|
930
|
+
)
|
|
1081
931
|
return _crud.require_dictionary_result(
|
|
1082
932
|
self._call(
|
|
1083
933
|
'activity_stream',
|
|
@@ -1163,7 +1013,10 @@ class Shotgun:
|
|
|
1163
1013
|
type, or if the server result is not a list.
|
|
1164
1014
|
ProtocolError: If a server request returns an HTTP error.
|
|
1165
1015
|
ValueError: If authenticated HTTP violates the configured origin
|
|
1166
|
-
policy.
|
|
1016
|
+
policy, or a naive datetime cannot be converted to UTC.
|
|
1017
|
+
OverflowError: If converting an aware datetime to UTC exceeds the
|
|
1018
|
+
supported datetime range.
|
|
1019
|
+
OSError: If the platform cannot resolve a local datetime.
|
|
1167
1020
|
"""
|
|
1168
1021
|
calls = _crud.build_batch_calls(requests)
|
|
1169
1022
|
if not calls:
|
|
@@ -1236,21 +1089,29 @@ class Shotgun:
|
|
|
1236
1089
|
)
|
|
1237
1090
|
|
|
1238
1091
|
def close(self) -> None:
|
|
1239
|
-
"""Retire known and current transports after in-flight work releases them.
|
|
1092
|
+
"""Retire known and current transports after in-flight work releases them.
|
|
1093
|
+
|
|
1094
|
+
Attempt the remaining immediately eligible closes if one fails, then
|
|
1095
|
+
propagate the first failure.
|
|
1096
|
+
|
|
1097
|
+
Raises:
|
|
1098
|
+
Exception: If a transport eligible for immediate cleanup fails to
|
|
1099
|
+
close.
|
|
1100
|
+
"""
|
|
1240
1101
|
close_after_unlock: list[Transport] = []
|
|
1241
1102
|
with self._transport_lock:
|
|
1242
1103
|
advance_transport_generation(self._config)
|
|
1243
|
-
if self._known_transport is not None and self._known_transport is not self.
|
|
1104
|
+
if self._known_transport is not None and self._known_transport is not self.transport:
|
|
1244
1105
|
retired = retire_transport(
|
|
1245
1106
|
self._lease_counts, self._retired_transports, self._known_transport
|
|
1246
1107
|
)
|
|
1247
1108
|
if retired is not None:
|
|
1248
1109
|
close_after_unlock.append(retired)
|
|
1249
|
-
transport = self.
|
|
1110
|
+
transport = self.transport
|
|
1250
1111
|
self._driver = None
|
|
1251
1112
|
self._driver_generation = None
|
|
1252
1113
|
self._known_transport = None
|
|
1253
|
-
self.
|
|
1114
|
+
self.transport = None
|
|
1254
1115
|
self._transport_owned = False
|
|
1255
1116
|
if transport is not None:
|
|
1256
1117
|
retired = retire_transport(self._lease_counts, self._retired_transports, transport)
|
|
@@ -1321,7 +1182,10 @@ class Shotgun:
|
|
|
1321
1182
|
file. A thumbnail failure occurs after the entity is created.
|
|
1322
1183
|
ProtocolError: If a server request returns an HTTP error.
|
|
1323
1184
|
ValueError: If authenticated HTTP violates the configured origin
|
|
1324
|
-
policy.
|
|
1185
|
+
policy, or a naive datetime cannot be converted to UTC.
|
|
1186
|
+
OverflowError: If converting an aware datetime to UTC exceeds the
|
|
1187
|
+
supported datetime range.
|
|
1188
|
+
OSError: If the platform cannot resolve a local datetime.
|
|
1325
1189
|
"""
|
|
1326
1190
|
field_data, thumbnails = _files.split_thumbnail_uploads(data, keep_image_none=False)
|
|
1327
1191
|
params = _crud.build_create_params(entity_type, field_data, return_fields)
|
|
@@ -1389,13 +1253,13 @@ class Shotgun:
|
|
|
1389
1253
|
|
|
1390
1254
|
Raises:
|
|
1391
1255
|
TypeError: If no attachment is given or the reference is a string.
|
|
1392
|
-
ValueError: If an entity dictionary references a different type
|
|
1256
|
+
ValueError: If an entity dictionary references a different type,
|
|
1257
|
+
server settings are incomplete, or authenticated HTTP violates
|
|
1258
|
+
the configured origin security policy.
|
|
1393
1259
|
ShotgunError: If another attachment reference is unsupported or a
|
|
1394
1260
|
setup RPC reports a fault; the fault keeps its specific type.
|
|
1395
1261
|
ShotgunFileDownloadError: If the resolved URL is invalid or setup,
|
|
1396
1262
|
transfer, or destination I/O fails.
|
|
1397
|
-
ValueError: If server settings are incomplete or authenticated HTTP
|
|
1398
|
-
violates the configured origin security policy.
|
|
1399
1263
|
"""
|
|
1400
1264
|
if attachment is False:
|
|
1401
1265
|
if attachment_id is None:
|
|
@@ -1430,7 +1294,7 @@ class Shotgun:
|
|
|
1430
1294
|
headers=headers,
|
|
1431
1295
|
url=url,
|
|
1432
1296
|
)
|
|
1433
|
-
return exchange.
|
|
1297
|
+
return exchange.execute(driver, operation)
|
|
1434
1298
|
except _errors.ShotgunFileDownloadError:
|
|
1435
1299
|
raise
|
|
1436
1300
|
except (TransportError, _errors.ProtocolError, OSError):
|
|
@@ -1445,54 +1309,36 @@ class Shotgun:
|
|
|
1445
1309
|
"""
|
|
1446
1310
|
raise _methods.entity_types_alias_error()
|
|
1447
1311
|
|
|
1448
|
-
@overload
|
|
1449
1312
|
def export_page(
|
|
1450
1313
|
self,
|
|
1451
1314
|
page_id: int,
|
|
1452
|
-
|
|
1453
|
-
/,
|
|
1315
|
+
format: str, # noqa: A002
|
|
1454
1316
|
layout_name: str | None = None,
|
|
1455
|
-
) -> str:
|
|
1456
|
-
|
|
1457
|
-
@overload
|
|
1458
|
-
def export_page(
|
|
1459
|
-
self,
|
|
1460
|
-
page_id: int,
|
|
1461
|
-
**kwargs: Unpack[_methods.ExportPageKeywordArguments],
|
|
1462
|
-
) -> str: ...
|
|
1463
|
-
|
|
1464
|
-
@_methods.expose_export_page_signature
|
|
1465
|
-
def export_page(self, *args: object, **kwargs: object) -> str:
|
|
1317
|
+
) -> str:
|
|
1466
1318
|
"""Export a page using the documented arguments.
|
|
1467
1319
|
|
|
1468
1320
|
The Page or its layout must be marked API Exportable in the web UI, or
|
|
1469
1321
|
the server rejects the export.
|
|
1470
1322
|
|
|
1471
1323
|
Args:
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
signature.
|
|
1324
|
+
page_id: Numeric page identifier.
|
|
1325
|
+
format: Required nonempty export format name.
|
|
1326
|
+
layout_name: Optional layout name, including an empty name.
|
|
1476
1327
|
|
|
1477
1328
|
Returns:
|
|
1478
1329
|
Exported page text returned by the server.
|
|
1479
1330
|
|
|
1480
1331
|
Raises:
|
|
1481
|
-
TypeError: If arguments do not match the documented signature.
|
|
1482
1332
|
ShotgunError: If an RPC fault or terminal transport failure occurs,
|
|
1483
|
-
or if
|
|
1333
|
+
or if `page_id`, `format`, or the server result is invalid.
|
|
1484
1334
|
ProtocolError: If a server request returns an HTTP error.
|
|
1485
1335
|
ValueError: If authenticated HTTP violates the configured origin
|
|
1486
1336
|
policy.
|
|
1487
1337
|
"""
|
|
1488
|
-
options = _methods.
|
|
1338
|
+
options = _methods.ExportPageOptions(page_id, format, layout_name)
|
|
1489
1339
|
params = _methods.build_export_page_params(options)
|
|
1490
1340
|
return _methods.require_string_result(self._call('export_page', params), 'export_page')
|
|
1491
1341
|
|
|
1492
|
-
@overload
|
|
1493
|
-
def find(self, entity_type: Never) -> list[dict[str, object]]: ...
|
|
1494
|
-
|
|
1495
|
-
@overload
|
|
1496
1342
|
def find(
|
|
1497
1343
|
self,
|
|
1498
1344
|
entity_type: str,
|
|
@@ -1505,33 +1351,50 @@ class Shotgun:
|
|
|
1505
1351
|
page: int = 0,
|
|
1506
1352
|
include_archived_projects: bool = True,
|
|
1507
1353
|
additional_filter_presets: object = None,
|
|
1508
|
-
) -> list[dict[str, object]]:
|
|
1509
|
-
|
|
1510
|
-
@_crud.expose_find_signature
|
|
1511
|
-
def find(self, *args: object, **kwargs: object) -> list[dict[str, object]]:
|
|
1354
|
+
) -> list[dict[str, object]]:
|
|
1512
1355
|
"""Find entities matching the supplied filters.
|
|
1513
1356
|
|
|
1514
1357
|
Args:
|
|
1515
|
-
|
|
1516
|
-
|
|
1358
|
+
entity_type: Entity type to find.
|
|
1359
|
+
filters: Filters in list or dict syntax.
|
|
1360
|
+
fields: Optional fields to return; defaults to `id`.
|
|
1361
|
+
order: Optional field and direction sort specifications.
|
|
1362
|
+
filter_operator: `'all'` or `'any'` for list-syntax filters.
|
|
1363
|
+
limit: Maximum entities to return, or `0` for no limit.
|
|
1364
|
+
retired_only: Return retired entities instead of active entities.
|
|
1365
|
+
page: Specific page to return, or `0` to read all pages.
|
|
1366
|
+
include_archived_projects: Include entities from archived projects.
|
|
1367
|
+
additional_filter_presets: Optional server-side filter presets.
|
|
1517
1368
|
|
|
1518
1369
|
Returns:
|
|
1519
1370
|
Matching entities in server order.
|
|
1520
1371
|
|
|
1521
1372
|
Raises:
|
|
1522
|
-
TypeError: If arguments do not match the documented signature.
|
|
1523
1373
|
ShotgunError: If an RPC fault or terminal transport failure occurs,
|
|
1524
|
-
or if filters, paging, ordering, or a server result is
|
|
1374
|
+
or if filters, fields, paging, ordering, or a server result is
|
|
1375
|
+
invalid.
|
|
1525
1376
|
ProtocolError: If a server request returns an HTTP error.
|
|
1526
1377
|
ValueError: If authenticated HTTP violates the configured origin
|
|
1527
|
-
policy.
|
|
1378
|
+
policy, or a naive datetime cannot be converted to UTC.
|
|
1379
|
+
OverflowError: If converting an aware datetime to UTC exceeds the
|
|
1380
|
+
supported datetime range.
|
|
1381
|
+
OSError: If the platform cannot resolve a local datetime.
|
|
1528
1382
|
"""
|
|
1529
|
-
return self._find(
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1383
|
+
return self._find(
|
|
1384
|
+
_crud.FindOptions(
|
|
1385
|
+
entity_type,
|
|
1386
|
+
filters,
|
|
1387
|
+
fields,
|
|
1388
|
+
order,
|
|
1389
|
+
filter_operator,
|
|
1390
|
+
limit,
|
|
1391
|
+
retired_only,
|
|
1392
|
+
page,
|
|
1393
|
+
include_archived_projects,
|
|
1394
|
+
additional_filter_presets,
|
|
1395
|
+
)
|
|
1396
|
+
)
|
|
1533
1397
|
|
|
1534
|
-
@overload
|
|
1535
1398
|
def find_one(
|
|
1536
1399
|
self,
|
|
1537
1400
|
entity_type: str,
|
|
@@ -1542,28 +1405,43 @@ class Shotgun:
|
|
|
1542
1405
|
retired_only: bool = False,
|
|
1543
1406
|
include_archived_projects: bool = True,
|
|
1544
1407
|
additional_filter_presets: object = None,
|
|
1545
|
-
) -> dict[str, object] | None:
|
|
1546
|
-
|
|
1547
|
-
@_crud.expose_find_one_signature
|
|
1548
|
-
def find_one(self, *args: object, **kwargs: object) -> dict[str, object] | None:
|
|
1408
|
+
) -> dict[str, object] | None:
|
|
1549
1409
|
"""Return the first entity matching the supplied filters.
|
|
1550
1410
|
|
|
1551
1411
|
Args:
|
|
1552
|
-
|
|
1553
|
-
|
|
1412
|
+
entity_type: Entity type to find.
|
|
1413
|
+
filters: Filters in list or dict syntax.
|
|
1414
|
+
fields: Optional fields to return; defaults to `id`.
|
|
1415
|
+
order: Optional field and direction sort specifications.
|
|
1416
|
+
filter_operator: `'all'` or `'any'` for list-syntax filters.
|
|
1417
|
+
retired_only: Return a retired entity instead of an active entity.
|
|
1418
|
+
include_archived_projects: Include entities from archived projects.
|
|
1419
|
+
additional_filter_presets: Optional server-side filter presets.
|
|
1554
1420
|
|
|
1555
1421
|
Returns:
|
|
1556
1422
|
The first matching entity, or `None` when no entity matches.
|
|
1557
1423
|
|
|
1558
1424
|
Raises:
|
|
1559
|
-
TypeError: If arguments do not match the documented signature.
|
|
1560
1425
|
ShotgunError: If an RPC fault or terminal transport failure occurs,
|
|
1561
|
-
or if filters, paging, ordering, or a server result is
|
|
1426
|
+
or if filters, fields, paging, ordering, or a server result is
|
|
1427
|
+
invalid.
|
|
1562
1428
|
ProtocolError: If a server request returns an HTTP error.
|
|
1563
1429
|
ValueError: If authenticated HTTP violates the configured origin
|
|
1564
|
-
policy.
|
|
1430
|
+
policy, or a naive datetime cannot be converted to UTC.
|
|
1431
|
+
OverflowError: If converting an aware datetime to UTC exceeds the
|
|
1432
|
+
supported datetime range.
|
|
1433
|
+
OSError: If the platform cannot resolve a local datetime.
|
|
1565
1434
|
"""
|
|
1566
|
-
options = _crud.
|
|
1435
|
+
options = _crud.FindOneOptions(
|
|
1436
|
+
entity_type,
|
|
1437
|
+
filters,
|
|
1438
|
+
fields,
|
|
1439
|
+
order,
|
|
1440
|
+
filter_operator,
|
|
1441
|
+
retired_only,
|
|
1442
|
+
include_archived_projects,
|
|
1443
|
+
additional_filter_presets,
|
|
1444
|
+
)
|
|
1567
1445
|
return _crud.first_result(self._find(_crud.find_options_from_one(options)))
|
|
1568
1446
|
|
|
1569
1447
|
def follow(self, user: dict[str, Any], entity: dict[str, Any]) -> dict[str, object]:
|
|
@@ -1713,16 +1591,20 @@ class Shotgun:
|
|
|
1713
1591
|
def _initialize(self, options: ConstructorOptions) -> None:
|
|
1714
1592
|
"""Initialize client state from validated constructor options."""
|
|
1715
1593
|
self._base_url = options.base_url.rstrip('/')
|
|
1716
|
-
self._ca_certs =
|
|
1594
|
+
self._ca_certs = (
|
|
1595
|
+
options.ca_certs or os.environ.get('SHOTGUN_API_CACERTS') or None
|
|
1596
|
+
if self._in_process
|
|
1597
|
+
else config_module.constructor_ca_certs(options.ca_certs)
|
|
1598
|
+
)
|
|
1717
1599
|
self._client_caps = ClientCapabilities()
|
|
1718
|
-
self._config = build_config(options)
|
|
1600
|
+
self._config = build_config(options, in_process=self._in_process)
|
|
1719
1601
|
|
|
1720
1602
|
self._driver: Driver | None = None
|
|
1721
1603
|
self._driver_generation: int | None = None
|
|
1722
1604
|
self._known_transport: Transport | None = None
|
|
1723
1605
|
self._lease_counts: dict[int, int] = {}
|
|
1724
1606
|
self._retired_transports: dict[int, Transport] = {}
|
|
1725
|
-
self.
|
|
1607
|
+
self.transport: Transport | None = None
|
|
1726
1608
|
self._transport_lock = threading.Lock()
|
|
1727
1609
|
self._transport_owned = False
|
|
1728
1610
|
|
|
@@ -2000,7 +1882,10 @@ class Shotgun:
|
|
|
2000
1882
|
or if the server result is invalid.
|
|
2001
1883
|
ProtocolError: If a server request returns an HTTP error.
|
|
2002
1884
|
ValueError: If authenticated HTTP violates the configured origin
|
|
2003
|
-
policy.
|
|
1885
|
+
policy, or a naive datetime cannot be converted to UTC.
|
|
1886
|
+
OverflowError: If converting an aware datetime to UTC exceeds the
|
|
1887
|
+
supported datetime range.
|
|
1888
|
+
OSError: If the platform cannot resolve a local datetime.
|
|
2004
1889
|
"""
|
|
2005
1890
|
result = self._call(
|
|
2006
1891
|
'schema_field_create',
|
|
@@ -2096,7 +1981,10 @@ class Shotgun:
|
|
|
2096
1981
|
or if the server result is invalid.
|
|
2097
1982
|
ProtocolError: If a server request returns an HTTP error.
|
|
2098
1983
|
ValueError: If authenticated HTTP violates the configured origin
|
|
2099
|
-
policy.
|
|
1984
|
+
policy, or a naive datetime cannot be converted to UTC.
|
|
1985
|
+
OverflowError: If converting an aware datetime to UTC exceeds the
|
|
1986
|
+
supported datetime range.
|
|
1987
|
+
OSError: If the platform cannot resolve a local datetime.
|
|
2100
1988
|
"""
|
|
2101
1989
|
return _crud.require_boolean_result(
|
|
2102
1990
|
self._call(
|
|
@@ -2216,30 +2104,23 @@ class Shotgun:
|
|
|
2216
2104
|
source_entity,
|
|
2217
2105
|
filmstrip_thumbnail,
|
|
2218
2106
|
)
|
|
2219
|
-
if share.thumbnail_path is not None and 'field_name' in kwargs:
|
|
2220
|
-
raise TypeError("Shotgun.upload() got multiple values for argument 'field_name'")
|
|
2221
2107
|
prepared: _files.PreparedUpload | None = None
|
|
2222
2108
|
if share.thumbnail_path is not None:
|
|
2223
|
-
|
|
2224
|
-
(
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
prepared = _files.prepare_upload(
|
|
2237
|
-
_files.UploadOptions(
|
|
2238
|
-
arguments=arguments,
|
|
2239
|
-
upload_type='Thumbnail',
|
|
2240
|
-
filmstrip=filmstrip_thumbnail,
|
|
2241
|
-
)
|
|
2109
|
+
for keyword in kwargs:
|
|
2110
|
+
if keyword not in ('display_name', 'tag_list', 'created_at'):
|
|
2111
|
+
raise TypeError(
|
|
2112
|
+
f"Shotgun.share_thumbnail() got an unexpected keyword argument '{keyword}'"
|
|
2113
|
+
)
|
|
2114
|
+
arguments = _files.UploadArguments(
|
|
2115
|
+
entity_type=share.source_entity_type,
|
|
2116
|
+
entity_id=share.source_entity_id,
|
|
2117
|
+
path=share.thumbnail_path,
|
|
2118
|
+
field_name=_files.thumbnail_fields(filmstrip_thumbnail)[0],
|
|
2119
|
+
display_name=cast('str | None', kwargs.get('display_name')),
|
|
2120
|
+
tag_list=cast('str | None', kwargs.get('tag_list')),
|
|
2121
|
+
created_at=cast('_dt_module.datetime | None', kwargs.get('created_at')),
|
|
2242
2122
|
)
|
|
2123
|
+
prepared = _files.prepare_upload(_files.upload_options(arguments))
|
|
2243
2124
|
context = config_module.snapshot(self._config)
|
|
2244
2125
|
require_secure_rpc(context, include_auth=True)
|
|
2245
2126
|
with self._driver_lease(context) as driver:
|
|
@@ -2247,9 +2128,7 @@ class Shotgun:
|
|
|
2247
2128
|
attachment_id = self._upload_thumbnail_for(driver, context, prepared)
|
|
2248
2129
|
if len(share.entities) == 1:
|
|
2249
2130
|
return attachment_id
|
|
2250
|
-
field_name
|
|
2251
|
-
'filmstrip_image' if filmstrip_thumbnail else 'image'
|
|
2252
|
-
)
|
|
2131
|
+
field_name = _files.thumbnail_fields(filmstrip_thumbnail)[1]
|
|
2253
2132
|
ready = driver.poll(
|
|
2254
2133
|
lambda: self._thumbnail_source_ready(
|
|
2255
2134
|
driver,
|
|
@@ -2279,10 +2158,6 @@ class Shotgun:
|
|
|
2279
2158
|
filmstrip_thumbnail,
|
|
2280
2159
|
)
|
|
2281
2160
|
|
|
2282
|
-
@overload
|
|
2283
|
-
def summarize(self, entity_type: Never) -> dict[str, object]: ...
|
|
2284
|
-
|
|
2285
|
-
@overload
|
|
2286
2161
|
def summarize(
|
|
2287
2162
|
self,
|
|
2288
2163
|
entity_type: str,
|
|
@@ -2291,29 +2166,39 @@ class Shotgun:
|
|
|
2291
2166
|
filter_operator: str | None = None,
|
|
2292
2167
|
grouping: list[dict[str, Any]] | None = None,
|
|
2293
2168
|
include_archived_projects: bool = True,
|
|
2294
|
-
) -> dict[str, object]:
|
|
2295
|
-
|
|
2296
|
-
@_methods.expose_summarize_signature
|
|
2297
|
-
def summarize(self, *args: object, **kwargs: object) -> dict[str, object]:
|
|
2169
|
+
) -> dict[str, object]:
|
|
2298
2170
|
"""Summarize field data returned by a query.
|
|
2299
2171
|
|
|
2300
2172
|
Args:
|
|
2301
|
-
|
|
2302
|
-
|
|
2173
|
+
entity_type: Entity type to summarize.
|
|
2174
|
+
filters: Filters in list or dict syntax.
|
|
2175
|
+
summary_fields: List of `{'field': ..., 'type': ...}` summaries.
|
|
2176
|
+
filter_operator: `'all'` or `'any'` for list-syntax filters.
|
|
2177
|
+
grouping: Optional grouping specs.
|
|
2178
|
+
include_archived_projects: Include archived projects when `True`.
|
|
2303
2179
|
|
|
2304
2180
|
Returns:
|
|
2305
2181
|
Dict with `summaries` and (when grouped) `groups`.
|
|
2306
2182
|
|
|
2307
2183
|
Raises:
|
|
2308
|
-
TypeError: If arguments do not match the documented signature.
|
|
2309
2184
|
ShotgunError: If an RPC fault or terminal transport failure occurs,
|
|
2310
2185
|
or if `filters`, `summary_fields`, or the server result has the
|
|
2311
2186
|
wrong type.
|
|
2312
2187
|
ProtocolError: If a server request returns an HTTP error.
|
|
2313
2188
|
ValueError: If authenticated HTTP violates the configured origin
|
|
2314
|
-
policy.
|
|
2189
|
+
policy, or a naive datetime cannot be converted to UTC.
|
|
2190
|
+
OverflowError: If converting an aware datetime to UTC exceeds the
|
|
2191
|
+
supported datetime range.
|
|
2192
|
+
OSError: If the platform cannot resolve a local datetime.
|
|
2315
2193
|
"""
|
|
2316
|
-
options = _methods.
|
|
2194
|
+
options = _methods.SummarizeOptions(
|
|
2195
|
+
entity_type,
|
|
2196
|
+
filters,
|
|
2197
|
+
summary_fields,
|
|
2198
|
+
filter_operator,
|
|
2199
|
+
grouping,
|
|
2200
|
+
include_archived_projects,
|
|
2201
|
+
)
|
|
2317
2202
|
params = _methods.build_summarize_params(options)
|
|
2318
2203
|
return _crud.require_dictionary_result(self._call('summarize', params), 'summarize')
|
|
2319
2204
|
|
|
@@ -2324,7 +2209,7 @@ class Shotgun:
|
|
|
2324
2209
|
project_ids: list[int] | None = None,
|
|
2325
2210
|
limit: int | None = None,
|
|
2326
2211
|
) -> dict[str, object]:
|
|
2327
|
-
"""Search entity display names matching `text
|
|
2212
|
+
"""Search entity display names matching `text`.
|
|
2328
2213
|
|
|
2329
2214
|
Args:
|
|
2330
2215
|
text: Text to match.
|
|
@@ -2338,10 +2223,14 @@ class Shotgun:
|
|
|
2338
2223
|
|
|
2339
2224
|
Raises:
|
|
2340
2225
|
ShotgunError: If an RPC fault or terminal transport failure occurs,
|
|
2341
|
-
|
|
2226
|
+
if `entity_types` or the server result is not a dictionary, or
|
|
2227
|
+
if an entity filter is invalid.
|
|
2342
2228
|
ProtocolError: If a server request returns an HTTP error.
|
|
2343
2229
|
ValueError: If authenticated HTTP violates the configured origin
|
|
2344
|
-
policy.
|
|
2230
|
+
policy, or a naive datetime cannot be converted to UTC.
|
|
2231
|
+
OverflowError: If converting an aware datetime to UTC exceeds the
|
|
2232
|
+
supported datetime range.
|
|
2233
|
+
OSError: If the platform cannot resolve a local datetime.
|
|
2345
2234
|
"""
|
|
2346
2235
|
params = _methods.build_text_search_params(
|
|
2347
2236
|
text,
|
|
@@ -2409,7 +2298,10 @@ class Shotgun:
|
|
|
2409
2298
|
nonempty file. A thumbnail failure occurs after the update.
|
|
2410
2299
|
ProtocolError: If a server request returns an HTTP error.
|
|
2411
2300
|
ValueError: If authenticated HTTP violates the configured origin
|
|
2412
|
-
policy.
|
|
2301
|
+
policy, or a naive datetime cannot be converted to UTC.
|
|
2302
|
+
OverflowError: If converting an aware datetime to UTC exceeds the
|
|
2303
|
+
supported datetime range.
|
|
2304
|
+
OSError: If the platform cannot resolve a local datetime.
|
|
2413
2305
|
"""
|
|
2414
2306
|
field_data, thumbnails = _files.split_thumbnail_uploads(data, keep_image_none=True)
|
|
2415
2307
|
params = _crud.build_update_params(
|
|
@@ -2438,7 +2330,8 @@ class Shotgun:
|
|
|
2438
2330
|
user: Optional user entity to attribute the access to.
|
|
2439
2331
|
|
|
2440
2332
|
Raises:
|
|
2441
|
-
ShotgunError: If
|
|
2333
|
+
ShotgunError: If a project or user ID is invalid, or an RPC fault
|
|
2334
|
+
or terminal transport failure occurs.
|
|
2442
2335
|
ProtocolError: If a server request returns an HTTP error.
|
|
2443
2336
|
ValueError: If authenticated HTTP violates the configured origin
|
|
2444
2337
|
policy.
|
|
@@ -2451,10 +2344,6 @@ class Shotgun:
|
|
|
2451
2344
|
),
|
|
2452
2345
|
)
|
|
2453
2346
|
|
|
2454
|
-
@overload
|
|
2455
|
-
def upload(self, entity_type: Never) -> int: ...
|
|
2456
|
-
|
|
2457
|
-
@overload
|
|
2458
2347
|
def upload(
|
|
2459
2348
|
self,
|
|
2460
2349
|
entity_type: str,
|
|
@@ -2464,25 +2353,26 @@ class Shotgun:
|
|
|
2464
2353
|
display_name: str | None = None,
|
|
2465
2354
|
tag_list: str | None = None,
|
|
2466
2355
|
created_at: _dt_module.datetime | None = None,
|
|
2467
|
-
) -> int:
|
|
2468
|
-
|
|
2469
|
-
@_expose_upload_signature
|
|
2470
|
-
def upload(self, *args: object, **kwargs: object) -> int:
|
|
2356
|
+
) -> int:
|
|
2471
2357
|
"""Upload a file or thumbnail and return its Attachment ID.
|
|
2472
2358
|
|
|
2473
2359
|
A server requiring legacy form uploads raises `ShotgunError` before any
|
|
2474
2360
|
upload request is sent. Server capability reads may occur.
|
|
2475
2361
|
|
|
2476
2362
|
Args:
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2363
|
+
entity_type: Entity type receiving the upload.
|
|
2364
|
+
entity_id: Numeric identifier of the receiving entity.
|
|
2365
|
+
path: Existing non-empty file path as text or filesystem-encoded
|
|
2366
|
+
bytes.
|
|
2367
|
+
field_name: Optional file field receiving an Attachment.
|
|
2368
|
+
display_name: Optional Attachment display name.
|
|
2369
|
+
tag_list: Optional comma-delimited Attachment tags.
|
|
2370
|
+
created_at: Optional Attachment creation timestamp.
|
|
2480
2371
|
|
|
2481
2372
|
Returns:
|
|
2482
2373
|
Created Attachment ID.
|
|
2483
2374
|
|
|
2484
2375
|
Raises:
|
|
2485
|
-
TypeError: If arguments do not match the documented signature.
|
|
2486
2376
|
ShotgunError: If the file or an upload response is invalid, an RPC
|
|
2487
2377
|
fault or terminal transport failure occurs, or the server
|
|
2488
2378
|
requires legacy form uploads.
|
|
@@ -2490,23 +2380,10 @@ class Shotgun:
|
|
|
2490
2380
|
ValueError: If authenticated HTTP violates the configured origin
|
|
2491
2381
|
policy.
|
|
2492
2382
|
"""
|
|
2493
|
-
arguments =
|
|
2494
|
-
|
|
2495
|
-
'filmstrip_image',
|
|
2496
|
-
'filmstrip_thumb_image',
|
|
2497
|
-
'image',
|
|
2498
|
-
'thumb_image',
|
|
2499
|
-
}
|
|
2500
|
-
upload_type: Literal['Attachment', 'Thumbnail'] = (
|
|
2501
|
-
'Thumbnail' if arguments.field_name in thumbnail_fields else 'Attachment'
|
|
2502
|
-
)
|
|
2503
|
-
return self._upload(
|
|
2504
|
-
_files.UploadOptions(
|
|
2505
|
-
arguments=arguments,
|
|
2506
|
-
upload_type=upload_type,
|
|
2507
|
-
filmstrip=arguments.field_name in {'filmstrip_image', 'filmstrip_thumb_image'},
|
|
2508
|
-
)
|
|
2383
|
+
arguments = _files.UploadArguments(
|
|
2384
|
+
entity_type, entity_id, path, field_name, display_name, tag_list, created_at
|
|
2509
2385
|
)
|
|
2386
|
+
return self._upload(_files.upload_options(arguments))
|
|
2510
2387
|
|
|
2511
2388
|
def upload_filmstrip_thumbnail(
|
|
2512
2389
|
self,
|
|
@@ -2672,10 +2549,6 @@ class Shotgun:
|
|
|
2672
2549
|
'work_schedule_read',
|
|
2673
2550
|
)
|
|
2674
2551
|
|
|
2675
|
-
@overload
|
|
2676
|
-
def work_schedule_update(self, date: Never) -> dict[str, object]: ...
|
|
2677
|
-
|
|
2678
|
-
@overload
|
|
2679
2552
|
def work_schedule_update(
|
|
2680
2553
|
self,
|
|
2681
2554
|
date: _dt_module.date | str,
|
|
@@ -2684,30 +2557,31 @@ class Shotgun:
|
|
|
2684
2557
|
project: dict[str, Any] | None = None,
|
|
2685
2558
|
user: dict[str, Any] | None = None,
|
|
2686
2559
|
recalculate_field: str | None = None,
|
|
2687
|
-
) -> dict[str, object]:
|
|
2688
|
-
|
|
2689
|
-
@_methods.expose_work_schedule_update_signature
|
|
2690
|
-
def work_schedule_update(self, *args: object, **kwargs: object) -> dict[str, object]:
|
|
2691
|
-
"""Update a work schedule using the documented arguments.
|
|
2560
|
+
) -> dict[str, object]:
|
|
2561
|
+
"""Update a work schedule.
|
|
2692
2562
|
|
|
2693
2563
|
Args:
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2564
|
+
date: Date or exact `YYYY-MM-DD` string to update.
|
|
2565
|
+
working: Whether the date is a working day.
|
|
2566
|
+
description: Optional schedule description.
|
|
2567
|
+
project: Optional project entity restriction.
|
|
2568
|
+
user: Optional user entity restriction.
|
|
2569
|
+
recalculate_field: Optional field to recalculate.
|
|
2698
2570
|
|
|
2699
2571
|
Returns:
|
|
2700
2572
|
Updated work schedule data returned by the server.
|
|
2701
2573
|
|
|
2702
2574
|
Raises:
|
|
2703
|
-
TypeError: If arguments do not match the documented signature.
|
|
2704
2575
|
ShotgunError: If an RPC fault or terminal transport failure occurs,
|
|
2705
|
-
or if
|
|
2576
|
+
or if the date, project/user exclusivity, or server result is
|
|
2577
|
+
invalid.
|
|
2706
2578
|
ProtocolError: If a server request returns an HTTP error.
|
|
2707
2579
|
ValueError: If authenticated HTTP violates the configured origin
|
|
2708
2580
|
policy.
|
|
2709
2581
|
"""
|
|
2710
|
-
options = _methods.
|
|
2582
|
+
options = _methods.WorkScheduleUpdateOptions(
|
|
2583
|
+
date, working, description, project, user, recalculate_field
|
|
2584
|
+
)
|
|
2711
2585
|
params = _methods.build_work_schedule_update_params(options)
|
|
2712
2586
|
return _crud.require_dictionary_result(
|
|
2713
2587
|
self._call('work_schedule_update', params),
|