sg-python-api 0.1.0__py3-none-any.whl → 0.1.2__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.0.dist-info → sg_python_api-0.1.2.dist-info}/METADATA +15 -28
- {sg_python_api-0.1.0.dist-info → sg_python_api-0.1.2.dist-info}/RECORD +13 -13
- shotgun_api3/_async_client.py +151 -108
- shotgun_api3/_async_driver.py +2 -14
- shotgun_api3/_client.py +152 -119
- shotgun_api3/_config.py +2 -10
- shotgun_api3/_driver.py +4 -18
- shotgun_api3/_files.py +66 -107
- shotgun_api3/_methods.py +104 -80
- shotgun_api3/_protocol.py +0 -93
- shotgun_api3/_version.py +1 -1
- {sg_python_api-0.1.0.dist-info → sg_python_api-0.1.2.dist-info}/WHEEL +0 -0
- {sg_python_api-0.1.0.dist-info → sg_python_api-0.1.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: sg-python-api
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Python client for Autodesk Flow Production Tracking
|
|
5
5
|
Project-URL: Documentation, https://github.com/dactylo/sg-python-api/tree/main/docs
|
|
6
6
|
Project-URL: Homepage, https://github.com/dactylo/sg-python-api
|
|
@@ -44,9 +44,9 @@ This documentation uses SG for Flow Production Tracking, formerly named Shotgun
|
|
|
44
44
|
for application tests.
|
|
45
45
|
|
|
46
46
|
sg-python-api is an independent implementation of the documented API of Autodesk's Python client
|
|
47
|
-
`3.10.
|
|
48
|
-
site before replacing its production client. The [migration guide](https://github.com/dactylo/sg-python-api/blob/v0.1.
|
|
49
|
-
through the switch, and the [compatibility reference](https://github.com/dactylo/sg-python-api/blob/v0.1.
|
|
47
|
+
`3.10.3`. Some behavior differs on purpose, so validate your application's workflows against a test
|
|
48
|
+
site before replacing its production client. The [migration guide](https://github.com/dactylo/sg-python-api/blob/v0.1.2/docs/migration-guide.md) walks
|
|
49
|
+
through the switch, and the [compatibility reference](https://github.com/dactylo/sg-python-api/blob/v0.1.2/COMPATIBILITY.md) lists the differences.
|
|
50
50
|
|
|
51
51
|
## Installation
|
|
52
52
|
|
|
@@ -55,16 +55,9 @@ requests to a remote site require HTTPS.
|
|
|
55
55
|
|
|
56
56
|
`sg-python-api` and Autodesk's `shotgun-api3` both install the `shotgun_api3` package, so install
|
|
57
57
|
exactly one of them in a Python environment. If the official client is already installed, follow
|
|
58
|
-
the [migration steps](https://github.com/dactylo/sg-python-api/blob/v0.1.
|
|
58
|
+
the [migration steps](https://github.com/dactylo/sg-python-api/blob/v0.1.2/docs/migration-guide.md#install-the-replacement) to replace it.
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
your application:
|
|
62
|
-
|
|
63
|
-
```sh
|
|
64
|
-
python -m pip install sg-python-api
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
To install from a checkout instead, run:
|
|
60
|
+
From a checkout, install into the Python environment that runs your application:
|
|
68
61
|
|
|
69
62
|
```sh
|
|
70
63
|
python -m pip install .
|
|
@@ -74,12 +67,6 @@ The base installation provides the synchronous `Shotgun` client and both `mockgu
|
|
|
74
67
|
use the native asynchronous client, `AsyncShotgun`, install the `async` extra, which adds the
|
|
75
68
|
`httpx2` HTTP library:
|
|
76
69
|
|
|
77
|
-
```sh
|
|
78
|
-
python -m pip install 'sg-python-api[async]'
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
From a checkout, use:
|
|
82
|
-
|
|
83
70
|
```sh
|
|
84
71
|
python -m pip install '.[async]'
|
|
85
72
|
```
|
|
@@ -143,23 +130,23 @@ operation fails. Without the `async` extra, importing `AsyncShotgun` raises `Imp
|
|
|
143
130
|
|
|
144
131
|
Share an `AsyncShotgun` only among tasks on one event loop, and cancel its work by cancelling the
|
|
145
132
|
task. A cancelled write may already have reached the server, so check its outcome before repeating
|
|
146
|
-
it. The [async reference](https://github.com/dactylo/sg-python-api/blob/v0.1.
|
|
133
|
+
it. The [async reference](https://github.com/dactylo/sg-python-api/blob/v0.1.2/COMPATIBILITY.md#async-extension-surfaces) covers shutdown and
|
|
147
134
|
cancellation in detail.
|
|
148
135
|
|
|
149
136
|
## Documentation
|
|
150
137
|
|
|
151
138
|
| If you want to... | Read |
|
|
152
139
|
| ----------------------------------------------------- | ---------------------------------------------------------------------------------- |
|
|
153
|
-
| Replace Autodesk's client in an existing application | [Migration guide](https://github.com/dactylo/sg-python-api/blob/v0.1.
|
|
154
|
-
| Check what behaves differently from Autodesk's client | [Compatibility](https://github.com/dactylo/sg-python-api/blob/v0.1.
|
|
155
|
-
| Tune pooling and page prefetch, or observe requests | [Configuration extensions](https://github.com/dactylo/sg-python-api/blob/v0.1.
|
|
156
|
-
| Confirm which client loads and run a smoke test | [Testing an installation](https://github.com/dactylo/sg-python-api/blob/v0.1.
|
|
157
|
-
| Compare measured latency and transfer memory | [Benchmarks](https://github.com/dactylo/sg-python-api/blob/v0.1.
|
|
158
|
-
| See changes by version | [Changelog](https://github.com/dactylo/sg-python-api/blob/v0.1.
|
|
140
|
+
| Replace Autodesk's client in an existing application | [Migration guide](https://github.com/dactylo/sg-python-api/blob/v0.1.2/docs/migration-guide.md) |
|
|
141
|
+
| Check what behaves differently from Autodesk's client | [Compatibility](https://github.com/dactylo/sg-python-api/blob/v0.1.2/COMPATIBILITY.md) |
|
|
142
|
+
| Tune pooling and page prefetch, or observe requests | [Configuration extensions](https://github.com/dactylo/sg-python-api/blob/v0.1.2/COMPATIBILITY.md#configuration-and-observer-extensions) |
|
|
143
|
+
| Confirm which client loads and run a smoke test | [Testing an installation](https://github.com/dactylo/sg-python-api/blob/v0.1.2/docs/testing.md) |
|
|
144
|
+
| Compare measured latency and transfer memory | [Benchmarks](https://github.com/dactylo/sg-python-api/blob/v0.1.2/docs/benchmarks.md) |
|
|
145
|
+
| See changes by version | [Changelog](https://github.com/dactylo/sg-python-api/blob/v0.1.2/CHANGELOG.md) |
|
|
159
146
|
|
|
160
147
|
## Development
|
|
161
148
|
|
|
162
|
-
See the [development guide](https://github.com/dactylo/sg-python-api/blob/v0.1.
|
|
149
|
+
See the [development guide](https://github.com/dactylo/sg-python-api/blob/v0.1.2/docs/development.md) for the required tools, CI, and dependency locks.
|
|
163
150
|
With those tools installed, run:
|
|
164
151
|
|
|
165
152
|
```sh
|
|
@@ -172,6 +159,6 @@ make check
|
|
|
172
159
|
|
|
173
160
|
## License
|
|
174
161
|
|
|
175
|
-
sg-python-api is available under the [MIT License](https://github.com/dactylo/sg-python-api/blob/v0.1.
|
|
162
|
+
sg-python-api is available under the [MIT License](https://github.com/dactylo/sg-python-api/blob/v0.1.2/LICENSE). It is an independent project and is
|
|
176
163
|
not affiliated with or endorsed by Autodesk. Flow Production Tracking is a product of Autodesk,
|
|
177
164
|
Inc.
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
shotgun_api3/__init__.py,sha256=fviJGOi_Gb9jHi5Q9ty5tIbeIvxMtLNrKx_4HJVgemI,2011
|
|
2
|
-
shotgun_api3/_async_client.py,sha256=
|
|
3
|
-
shotgun_api3/_async_driver.py,sha256=
|
|
2
|
+
shotgun_api3/_async_client.py,sha256=UYVk_IGzMcUguJ4oCV-Nof4mL2kvzYYGuiYvW4gHeMs,113167
|
|
3
|
+
shotgun_api3/_async_driver.py,sha256=NnuMmQP5KrAoANBvWIhcIUe_ljD62pK_7xSIoEIltXw,32308
|
|
4
4
|
shotgun_api3/_async_httpx2.py,sha256=3pjeFsb5racGArvlR50c3w0XtrttXuRU_6E9Y-cBU3c,24387
|
|
5
5
|
shotgun_api3/_async_transport.py,sha256=8iAcoFafEHKRBirBkqdIqMFgqLs1YTgtzgACudD0kM4,4928
|
|
6
6
|
shotgun_api3/_capabilities.py,sha256=RrStvExVC3TAADhfbY2JpYZUXmvE63vXIJy1R-nkEII,5527
|
|
7
|
-
shotgun_api3/_client.py,sha256=
|
|
8
|
-
shotgun_api3/_config.py,sha256=
|
|
7
|
+
shotgun_api3/_client.py,sha256=jtemxhdhFr1gwE7qB6K-62Sohb2C_S4dEO7uKpVh2Uo,102109
|
|
8
|
+
shotgun_api3/_config.py,sha256=fALxy5xGI3A0nECsRDyls_9A8tvjB0DNSpTu1agNEHw,54931
|
|
9
9
|
shotgun_api3/_crud.py,sha256=Ax36jA2E-lauRf2D-2rmRDj61SilOygtkjKgs5XDCUs,30319
|
|
10
|
-
shotgun_api3/_driver.py,sha256=
|
|
10
|
+
shotgun_api3/_driver.py,sha256=DAtnZW044TWiqscs0G1uwTiluAFtCoR2wKTbJYJHT2g,29498
|
|
11
11
|
shotgun_api3/_errors.py,sha256=fk7v3XbmZK63M272r5wDwF_GgI-4RynPfAWv1P-J-GI,1480
|
|
12
12
|
shotgun_api3/_execution.py,sha256=Kn2Yd9sXIA975stnof7MeuA8bT3dyOuWDIqQnP65LO0,8235
|
|
13
|
-
shotgun_api3/_files.py,sha256
|
|
14
|
-
shotgun_api3/_methods.py,sha256=
|
|
15
|
-
shotgun_api3/_protocol.py,sha256=
|
|
13
|
+
shotgun_api3/_files.py,sha256=-eXHyG0U9mEAdYTthgVEhlzBKYUOt4g-3k9D522L3zM,33900
|
|
14
|
+
shotgun_api3/_methods.py,sha256=pYzx2pN0nus6vPWf-Gl8Zz4MgRf8R4b7kvxN8lhoXgc,37685
|
|
15
|
+
shotgun_api3/_protocol.py,sha256=0ccL65aIm3v2w6dOtNnZuFrKQncA8WO4yadtxRP55-w,42194
|
|
16
16
|
shotgun_api3/_sentinel.py,sha256=KAQzQjJVhTTZPLFY1f88-_vP7U06i2g6ZS7KJcn4vIA,116
|
|
17
17
|
shotgun_api3/_sg_timezone.py,sha256=yr7Wdln9fwfTVGMQSFsgO-eduuTHQ5EbSY5xEVQ2tYw,115
|
|
18
18
|
shotgun_api3/_signatures.py,sha256=_yhNnbkVF-0opaBfg9H6SauBN2RT4hJsHGa3ZO3Ug4s,1622
|
|
19
19
|
shotgun_api3/_transport.py,sha256=LmQ0e2VvAKwFdNy4SyfRHwgKC6GWnwkIN5Wa2fin3AM,30047
|
|
20
|
-
shotgun_api3/_version.py,sha256=
|
|
20
|
+
shotgun_api3/_version.py,sha256=0NYED9oy2nGCvTERMwWJvajshS5qzH_v4w7QUAGAivY,102
|
|
21
21
|
shotgun_api3/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
22
|
shotgun_api3/shotgun.py,sha256=X7PLlCC-gR8dJgY_uLYXw_LWN8mz5MsQsSYJldtavTk,1706
|
|
23
23
|
shotgun_api3/lib/__init__.py,sha256=4WGYod6xHcj23rapx5bTDGdjT52H1CAQNMz4BmzNmn0,55
|
|
@@ -25,7 +25,7 @@ shotgun_api3/lib/sgtimezone.py,sha256=nYSaCsIeq_SJh7YgL4yWN7dTVVz9lAfx-G3mzsHb8i
|
|
|
25
25
|
shotgun_api3/lib/mockgun/__init__.py,sha256=2mHjMJAV4mZ8JvnP8WHn6tkdMJoB7UQtNSs99YzNW30,703
|
|
26
26
|
shotgun_api3/lib/mockgun/_async.py,sha256=7bTZFdlSzeoGq9fRbPBAf-X08qDmrkzV9rxskx5AGX8,10812
|
|
27
27
|
shotgun_api3/lib/mockgun/_mockgun.py,sha256=k2cqLMCKpU5oIbUGiYulf1aIU0HLrMB6DQQ3KrCy7WQ,65093
|
|
28
|
-
sg_python_api-0.1.
|
|
29
|
-
sg_python_api-0.1.
|
|
30
|
-
sg_python_api-0.1.
|
|
31
|
-
sg_python_api-0.1.
|
|
28
|
+
sg_python_api-0.1.2.dist-info/METADATA,sha256=2Zv6g9pJZ28QttHMO6Q1yYWvyczPypCHc-QCAYbjIaQ,7587
|
|
29
|
+
sg_python_api-0.1.2.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
30
|
+
sg_python_api-0.1.2.dist-info/licenses/LICENSE,sha256=V3moMsQxKDchTd3mtXl5J-ODaNBDvFrapOf1DK7Nx_U,1082
|
|
31
|
+
sg_python_api-0.1.2.dist-info/RECORD,,
|
shotgun_api3/_async_client.py
CHANGED
|
@@ -51,7 +51,6 @@ from ._client import (
|
|
|
51
51
|
expose_constructor_signature,
|
|
52
52
|
)
|
|
53
53
|
from ._config import (
|
|
54
|
-
CompatibilityWarningCode,
|
|
55
54
|
Config,
|
|
56
55
|
RequestContext,
|
|
57
56
|
advance_transport_generation,
|
|
@@ -60,7 +59,6 @@ from ._config import (
|
|
|
60
59
|
server_host,
|
|
61
60
|
server_page_limit,
|
|
62
61
|
)
|
|
63
|
-
from ._errors import ShotgunError
|
|
64
62
|
from ._execution import SuppressedExceptionCapture, release_lease, retire_transport
|
|
65
63
|
from ._signatures import bind_arguments, expose_signature
|
|
66
64
|
from ._transport import (
|
|
@@ -288,7 +286,6 @@ class _InvocationOptions:
|
|
|
288
286
|
"""Collect non-payload controls for one client invocation."""
|
|
289
287
|
|
|
290
288
|
auth_spec: _protocol.AuthSpec | None = None
|
|
291
|
-
compatibility_warning_codes: tuple[CompatibilityWarningCode, ...] = ()
|
|
292
289
|
include_auth: bool = True
|
|
293
290
|
logical_method_name: str | None = None
|
|
294
291
|
|
|
@@ -523,7 +520,6 @@ class AsyncShotgun:
|
|
|
523
520
|
outbound,
|
|
524
521
|
context,
|
|
525
522
|
include_auth=invocation.options.include_auth,
|
|
526
|
-
compatibility_warning_codes=invocation.options.compatibility_warning_codes,
|
|
527
523
|
_logical_method_name=invocation.options.logical_method_name,
|
|
528
524
|
)
|
|
529
525
|
return _protocol.transform_inbound(result, context.convert_datetimes_to_utc)
|
|
@@ -1040,29 +1036,6 @@ class AsyncShotgun:
|
|
|
1040
1036
|
lambda _text, _headers: None,
|
|
1041
1037
|
)
|
|
1042
1038
|
|
|
1043
|
-
@staticmethod
|
|
1044
|
-
async def _upload_form(
|
|
1045
|
-
driver: AsyncDriver,
|
|
1046
|
-
context: RequestContext,
|
|
1047
|
-
prepared: _files.PreparedUpload,
|
|
1048
|
-
) -> Never:
|
|
1049
|
-
"""Send the observed form request without guessing a success result."""
|
|
1050
|
-
if context.canonical_origin is None:
|
|
1051
|
-
raise ValueError('server parameters must be configured before upload I/O')
|
|
1052
|
-
exchange = _files.build_form_upload_exchange(
|
|
1053
|
-
context.canonical_origin,
|
|
1054
|
-
context.user_agent,
|
|
1055
|
-
prepared,
|
|
1056
|
-
context.auth,
|
|
1057
|
-
chunk_size=_ASYNC_FILE_BATCH_SIZE,
|
|
1058
|
-
)
|
|
1059
|
-
|
|
1060
|
-
def reject_success(_text: str, _headers: Mapping[str, str]) -> Never:
|
|
1061
|
-
raise ShotgunError('form upload success response is not established')
|
|
1062
|
-
|
|
1063
|
-
await _execute_upload_exchange(driver, context, exchange, reject_success)
|
|
1064
|
-
raise AssertionError('form upload response parser returned')
|
|
1065
|
-
|
|
1066
1039
|
@staticmethod
|
|
1067
1040
|
async def _upload_link(
|
|
1068
1041
|
driver: AsyncDriver,
|
|
@@ -1165,14 +1138,14 @@ class AsyncShotgun:
|
|
|
1165
1138
|
arguments = prepared.options.arguments
|
|
1166
1139
|
capabilities = await self._ensure_readiness(context, driver)
|
|
1167
1140
|
operation_context = await self._authenticated_context(context, driver)
|
|
1168
|
-
upload_path = _files.
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1141
|
+
upload_path = _files.require_supported_upload_path(
|
|
1142
|
+
_files.choose_upload_path(
|
|
1143
|
+
capabilities.server_info,
|
|
1144
|
+
arguments.entity_type,
|
|
1145
|
+
arguments.field_name,
|
|
1146
|
+
prepared.file_size,
|
|
1147
|
+
)
|
|
1173
1148
|
)
|
|
1174
|
-
if upload_path == 'form':
|
|
1175
|
-
return await self._upload_form(driver, operation_context, prepared)
|
|
1176
1149
|
multipart = upload_path == 'multipart'
|
|
1177
1150
|
upload_info = await self._upload_allocation(
|
|
1178
1151
|
driver,
|
|
@@ -1211,6 +1184,16 @@ class AsyncShotgun:
|
|
|
1211
1184
|
prepared: _files.PreparedUpload,
|
|
1212
1185
|
) -> int:
|
|
1213
1186
|
"""Execute the exact direct-storage thumbnail workflow."""
|
|
1187
|
+
capabilities = await self._ensure_readiness(context, driver)
|
|
1188
|
+
arguments = prepared.options.arguments
|
|
1189
|
+
_files.require_supported_upload_path(
|
|
1190
|
+
_files.choose_upload_path(
|
|
1191
|
+
capabilities.server_info,
|
|
1192
|
+
arguments.entity_type,
|
|
1193
|
+
arguments.field_name,
|
|
1194
|
+
prepared.file_size,
|
|
1195
|
+
)
|
|
1196
|
+
)
|
|
1214
1197
|
upload_info = await self._upload_allocation(
|
|
1215
1198
|
driver,
|
|
1216
1199
|
context,
|
|
@@ -1220,6 +1203,28 @@ class AsyncShotgun:
|
|
|
1220
1203
|
await self._upload_direct(driver, context, prepared, upload_info)
|
|
1221
1204
|
return await self._upload_link(driver, context, prepared, upload_info)
|
|
1222
1205
|
|
|
1206
|
+
async def _upload_thumbnails_after_write(
|
|
1207
|
+
self,
|
|
1208
|
+
entity_type: str,
|
|
1209
|
+
entity_id: int,
|
|
1210
|
+
thumbnails: dict[str, object],
|
|
1211
|
+
result: dict[str, object],
|
|
1212
|
+
) -> dict[str, object]:
|
|
1213
|
+
"""Upload separated thumbnail paths and merge their current field values."""
|
|
1214
|
+
if not thumbnails:
|
|
1215
|
+
return result
|
|
1216
|
+
for field_name, path in thumbnails.items():
|
|
1217
|
+
upload = (
|
|
1218
|
+
self.upload_filmstrip_thumbnail
|
|
1219
|
+
if field_name == 'filmstrip_image'
|
|
1220
|
+
else self.upload_thumbnail
|
|
1221
|
+
)
|
|
1222
|
+
await upload(entity_type, entity_id, cast('str', path))
|
|
1223
|
+
current = await self.find_one(entity_type, [['id', 'is', entity_id]], list(thumbnails))
|
|
1224
|
+
if current is not None:
|
|
1225
|
+
result.update({field_name: current.get(field_name) for field_name in thumbnails})
|
|
1226
|
+
return result
|
|
1227
|
+
|
|
1223
1228
|
@overload
|
|
1224
1229
|
async def activity_stream_read(self, entity_type: Never) -> dict[str, object]: ...
|
|
1225
1230
|
|
|
@@ -1520,6 +1525,10 @@ class AsyncShotgun:
|
|
|
1520
1525
|
) -> dict[str, object]:
|
|
1521
1526
|
"""Create an entity with the supplied field values.
|
|
1522
1527
|
|
|
1528
|
+
Non-empty `image` and `filmstrip_image` values are file paths. They are
|
|
1529
|
+
uploaded as thumbnails after the entity is created, and the result
|
|
1530
|
+
includes their current field values.
|
|
1531
|
+
|
|
1523
1532
|
Args:
|
|
1524
1533
|
entity_type: Entity type to create.
|
|
1525
1534
|
data: Field values for the new entity.
|
|
@@ -1530,14 +1539,22 @@ class AsyncShotgun:
|
|
|
1530
1539
|
|
|
1531
1540
|
Raises:
|
|
1532
1541
|
ShotgunError: If an RPC fault or terminal transport failure occurs,
|
|
1533
|
-
|
|
1534
|
-
result is invalid
|
|
1542
|
+
if `data`, its field names, `return_fields`, or the server
|
|
1543
|
+
result is invalid, or if a thumbnail path is not a nonempty
|
|
1544
|
+
file. A thumbnail failure occurs after the entity is created.
|
|
1535
1545
|
ProtocolError: If a server request returns an HTTP error.
|
|
1536
1546
|
ValueError: If authenticated HTTP violates the configured origin
|
|
1537
1547
|
policy.
|
|
1538
1548
|
"""
|
|
1539
|
-
|
|
1540
|
-
|
|
1549
|
+
field_data, thumbnails = _files.split_thumbnail_uploads(data, keep_image_none=False)
|
|
1550
|
+
params = _crud.build_create_params(entity_type, field_data, return_fields)
|
|
1551
|
+
result = _crud.require_dictionary_result(await self._call('create', params), 'create')
|
|
1552
|
+
if not thumbnails:
|
|
1553
|
+
return result
|
|
1554
|
+
entity_id = _crud.require_entity_id(result.get('id'), 'create did not return an entity id')
|
|
1555
|
+
return await self._upload_thumbnails_after_write(
|
|
1556
|
+
entity_type, entity_id, thumbnails, result
|
|
1557
|
+
)
|
|
1541
1558
|
|
|
1542
1559
|
async def delete(self, entity_type: str, entity_id: int) -> bool:
|
|
1543
1560
|
"""Retire an entity.
|
|
@@ -1642,6 +1659,15 @@ class AsyncShotgun:
|
|
|
1642
1659
|
except (TransportError, _errors.ProtocolError, OSError):
|
|
1643
1660
|
raise _errors.ShotgunFileDownloadError('attachment download failed') from None
|
|
1644
1661
|
|
|
1662
|
+
async def entity_types(self) -> Never:
|
|
1663
|
+
"""Reject the deprecated alias of `schema_entity_read()` without I/O.
|
|
1664
|
+
|
|
1665
|
+
Raises:
|
|
1666
|
+
ShotgunError: Always, naming `schema_entity_read()` as the
|
|
1667
|
+
replacement.
|
|
1668
|
+
"""
|
|
1669
|
+
raise _methods.entity_types_alias_error()
|
|
1670
|
+
|
|
1645
1671
|
@overload
|
|
1646
1672
|
async def export_page(
|
|
1647
1673
|
self,
|
|
@@ -1662,6 +1688,9 @@ class AsyncShotgun:
|
|
|
1662
1688
|
async def export_page(self, *args: object, **kwargs: object) -> str:
|
|
1663
1689
|
"""Export a page using the documented arguments.
|
|
1664
1690
|
|
|
1691
|
+
The Page or its layout must be marked API Exportable in the web UI, or
|
|
1692
|
+
the server rejects the export.
|
|
1693
|
+
|
|
1665
1694
|
Args:
|
|
1666
1695
|
*args: Positional values from the documented `export_page`
|
|
1667
1696
|
signature.
|
|
@@ -1982,7 +2011,11 @@ class AsyncShotgun:
|
|
|
1982
2011
|
entity,
|
|
1983
2012
|
seed_entity_field,
|
|
1984
2013
|
)
|
|
1985
|
-
result = await self._call(
|
|
2014
|
+
result = await self._call(
|
|
2015
|
+
'nav_search',
|
|
2016
|
+
params,
|
|
2017
|
+
_InvocationOptions(logical_method_name='nav_search_entity'),
|
|
2018
|
+
)
|
|
1986
2019
|
return _methods.require_dictionary_list_result(result, 'nav_search_entity')
|
|
1987
2020
|
|
|
1988
2021
|
async def nav_search_string(
|
|
@@ -2013,7 +2046,11 @@ class AsyncShotgun:
|
|
|
2013
2046
|
search_string,
|
|
2014
2047
|
seed_entity_field,
|
|
2015
2048
|
)
|
|
2016
|
-
result = await self._call(
|
|
2049
|
+
result = await self._call(
|
|
2050
|
+
'nav_search',
|
|
2051
|
+
params,
|
|
2052
|
+
_InvocationOptions(logical_method_name='nav_search_string'),
|
|
2053
|
+
)
|
|
2017
2054
|
return _methods.require_dictionary_list_result(result, 'nav_search_string')
|
|
2018
2055
|
|
|
2019
2056
|
async def note_thread_read(
|
|
@@ -2038,7 +2075,11 @@ class AsyncShotgun:
|
|
|
2038
2075
|
policy.
|
|
2039
2076
|
"""
|
|
2040
2077
|
params = _methods.build_note_thread_read_params(note_id, entity_fields)
|
|
2041
|
-
result = await self._call(
|
|
2078
|
+
result = await self._call(
|
|
2079
|
+
'note_thread_contents',
|
|
2080
|
+
params,
|
|
2081
|
+
_InvocationOptions(logical_method_name='note_thread_read'),
|
|
2082
|
+
)
|
|
2042
2083
|
return _methods.require_dictionary_list_result(result, 'note_thread_read')
|
|
2043
2084
|
|
|
2044
2085
|
async def preferences_read(self, prefs: list[str] | None = None) -> dict[str, object]:
|
|
@@ -2085,6 +2126,18 @@ class AsyncShotgun:
|
|
|
2085
2126
|
params = _crud.build_entity_action_params(entity_type, entity_id)
|
|
2086
2127
|
return _crud.require_boolean_result(await self._call('revive', params), 'revive')
|
|
2087
2128
|
|
|
2129
|
+
async def schema(self, entity_type: str) -> Never:
|
|
2130
|
+
"""Reject the deprecated alias of `schema_field_read()` without I/O.
|
|
2131
|
+
|
|
2132
|
+
Args:
|
|
2133
|
+
entity_type: Entity type named in the replacement suggestion.
|
|
2134
|
+
|
|
2135
|
+
Raises:
|
|
2136
|
+
ShotgunError: Always, naming the equivalent `schema_field_read()`
|
|
2137
|
+
call.
|
|
2138
|
+
"""
|
|
2139
|
+
raise _methods.schema_alias_error(entity_type)
|
|
2140
|
+
|
|
2088
2141
|
async def schema_entity_read(
|
|
2089
2142
|
self,
|
|
2090
2143
|
project_entity: dict[str, Any] | None = None,
|
|
@@ -2104,34 +2157,12 @@ class AsyncShotgun:
|
|
|
2104
2157
|
ValueError: If authenticated HTTP violates the configured origin
|
|
2105
2158
|
policy.
|
|
2106
2159
|
"""
|
|
2107
|
-
warnings_codes = _methods.consume_compatibility_warnings(
|
|
2108
|
-
_methods.SCHEMA_ENTITY_READ_WARNINGS,
|
|
2109
|
-
self,
|
|
2110
|
-
)
|
|
2111
2160
|
result = await self._call(
|
|
2112
2161
|
'schema_entity_read',
|
|
2113
2162
|
_methods.build_schema_entity_read_params(project_entity),
|
|
2114
|
-
_InvocationOptions(compatibility_warning_codes=warnings_codes),
|
|
2115
2163
|
)
|
|
2116
2164
|
return _crud.require_dictionary_result(result, 'schema_entity_read')
|
|
2117
2165
|
|
|
2118
|
-
async def entity_types(self) -> dict[str, object]:
|
|
2119
|
-
"""Return entity schema through the deprecated alias.
|
|
2120
|
-
|
|
2121
|
-
Returns:
|
|
2122
|
-
Entity-type schema data returned by the server.
|
|
2123
|
-
|
|
2124
|
-
Raises:
|
|
2125
|
-
ShotgunError: If an RPC fault or terminal transport failure occurs,
|
|
2126
|
-
or if the server result is not a dictionary.
|
|
2127
|
-
ProtocolError: If a server request returns an HTTP error.
|
|
2128
|
-
ValueError: If authenticated HTTP violates the configured origin
|
|
2129
|
-
policy.
|
|
2130
|
-
"""
|
|
2131
|
-
_methods.warn_entity_types_alias()
|
|
2132
|
-
with _methods.entity_types_alias(self):
|
|
2133
|
-
return await self.schema_entity_read()
|
|
2134
|
-
|
|
2135
2166
|
async def schema_field_create(
|
|
2136
2167
|
self,
|
|
2137
2168
|
entity_type: str,
|
|
@@ -2210,10 +2241,6 @@ class AsyncShotgun:
|
|
|
2210
2241
|
ValueError: If authenticated HTTP violates the configured origin
|
|
2211
2242
|
policy.
|
|
2212
2243
|
"""
|
|
2213
|
-
warning_codes = _methods.consume_compatibility_warnings(
|
|
2214
|
-
_methods.SCHEMA_FIELD_READ_WARNINGS,
|
|
2215
|
-
self,
|
|
2216
|
-
)
|
|
2217
2244
|
result = await self._call(
|
|
2218
2245
|
'schema_field_read',
|
|
2219
2246
|
_methods.build_schema_field_read_params(
|
|
@@ -2221,30 +2248,9 @@ class AsyncShotgun:
|
|
|
2221
2248
|
field_name,
|
|
2222
2249
|
project_entity,
|
|
2223
2250
|
),
|
|
2224
|
-
_InvocationOptions(compatibility_warning_codes=warning_codes),
|
|
2225
2251
|
)
|
|
2226
2252
|
return _crud.require_dictionary_result(result, 'schema_field_read')
|
|
2227
2253
|
|
|
2228
|
-
async def schema(self, entity_type: str) -> dict[str, object]:
|
|
2229
|
-
"""Return field schema through the deprecated alias.
|
|
2230
|
-
|
|
2231
|
-
Args:
|
|
2232
|
-
entity_type: Entity type whose fields to return.
|
|
2233
|
-
|
|
2234
|
-
Returns:
|
|
2235
|
-
Field schema data returned by the server.
|
|
2236
|
-
|
|
2237
|
-
Raises:
|
|
2238
|
-
ShotgunError: If an RPC fault or terminal transport failure occurs,
|
|
2239
|
-
or if the server result is invalid.
|
|
2240
|
-
ProtocolError: If a server request returns an HTTP error.
|
|
2241
|
-
ValueError: If authenticated HTTP violates the configured origin
|
|
2242
|
-
policy.
|
|
2243
|
-
"""
|
|
2244
|
-
_methods.warn_schema_alias()
|
|
2245
|
-
with _methods.schema_alias(self):
|
|
2246
|
-
return await self.schema_field_read(entity_type)
|
|
2247
|
-
|
|
2248
2254
|
async def schema_field_update(
|
|
2249
2255
|
self,
|
|
2250
2256
|
entity_type: str,
|
|
@@ -2352,7 +2358,8 @@ class AsyncShotgun:
|
|
|
2352
2358
|
|
|
2353
2359
|
Supply exactly one of `thumbnail_path` and `source_entity`. A local
|
|
2354
2360
|
thumbnail is uploaded to the first target before it is shared with the
|
|
2355
|
-
remaining targets.
|
|
2361
|
+
remaining targets. A local thumbnail is rejected before any upload
|
|
2362
|
+
request if the server requires legacy form uploads.
|
|
2356
2363
|
|
|
2357
2364
|
Args:
|
|
2358
2365
|
entities: Nonempty list of target entities with `type` and `id`.
|
|
@@ -2369,7 +2376,8 @@ class AsyncShotgun:
|
|
|
2369
2376
|
TypeError: If forwarded arguments do not match the upload signature
|
|
2370
2377
|
or include `field_name`.
|
|
2371
2378
|
ShotgunError: If an RPC fault or terminal transport failure occurs,
|
|
2372
|
-
or if the source selection, entities, or transport fails
|
|
2379
|
+
or if the source selection, entities, or transport fails, or a
|
|
2380
|
+
local upload requires the legacy form route.
|
|
2373
2381
|
ShotgunThumbnailNotReady: If an uploaded source stays transient.
|
|
2374
2382
|
ProtocolError: If an upload endpoint returns an HTTP error.
|
|
2375
2383
|
ValueError: If authenticated HTTP violates the configured origin
|
|
@@ -2559,6 +2567,12 @@ class AsyncShotgun:
|
|
|
2559
2567
|
) -> dict[str, object]:
|
|
2560
2568
|
"""Update fields on an existing entity.
|
|
2561
2569
|
|
|
2570
|
+
Non-empty `image` and `filmstrip_image` values are file paths. They are
|
|
2571
|
+
uploaded as thumbnails after the other fields are updated, and the
|
|
2572
|
+
result includes their current field values. An `image` of `None` clears
|
|
2573
|
+
both thumbnails. When no other fields remain, no update request is sent
|
|
2574
|
+
and the result contains only `id` and `type`.
|
|
2575
|
+
|
|
2562
2576
|
Args:
|
|
2563
2577
|
entity_type: Entity type to update.
|
|
2564
2578
|
entity_id: Numeric entity identifier.
|
|
@@ -2570,19 +2584,29 @@ class AsyncShotgun:
|
|
|
2570
2584
|
|
|
2571
2585
|
Raises:
|
|
2572
2586
|
ShotgunError: If an RPC fault or terminal transport failure occurs,
|
|
2573
|
-
|
|
2574
|
-
|
|
2587
|
+
if `data`, its field names, `multi_entity_update_modes`, or the
|
|
2588
|
+
server result is invalid, or if a thumbnail path is not a
|
|
2589
|
+
nonempty file. A thumbnail failure occurs after the update.
|
|
2575
2590
|
ProtocolError: If a server request returns an HTTP error.
|
|
2576
2591
|
ValueError: If authenticated HTTP violates the configured origin
|
|
2577
2592
|
policy.
|
|
2578
2593
|
"""
|
|
2594
|
+
field_data, thumbnails = _files.split_thumbnail_uploads(data, keep_image_none=True)
|
|
2579
2595
|
params = _crud.build_update_params(
|
|
2580
2596
|
entity_type,
|
|
2581
2597
|
entity_id,
|
|
2582
|
-
|
|
2598
|
+
field_data,
|
|
2583
2599
|
multi_entity_update_modes,
|
|
2584
2600
|
)
|
|
2585
|
-
|
|
2601
|
+
result: dict[str, object] = {'id': entity_id, 'type': entity_type}
|
|
2602
|
+
if params['fields']:
|
|
2603
|
+
result = _crud.require_dictionary_result(
|
|
2604
|
+
await self._call('update', params),
|
|
2605
|
+
'update',
|
|
2606
|
+
)
|
|
2607
|
+
return await self._upload_thumbnails_after_write(
|
|
2608
|
+
entity_type, entity_id, thumbnails, result
|
|
2609
|
+
)
|
|
2586
2610
|
|
|
2587
2611
|
async def update_project_last_accessed(
|
|
2588
2612
|
self,
|
|
@@ -2626,9 +2650,8 @@ class AsyncShotgun:
|
|
|
2626
2650
|
async def upload(self, *args: object, **kwargs: object) -> int:
|
|
2627
2651
|
"""Upload a file or thumbnail and return its Attachment ID.
|
|
2628
2652
|
|
|
2629
|
-
A
|
|
2630
|
-
|
|
2631
|
-
The form request has already been sent when this error is raised.
|
|
2653
|
+
A server requiring legacy form uploads raises `ShotgunError` before any
|
|
2654
|
+
upload request is sent. Server capability reads may occur.
|
|
2632
2655
|
|
|
2633
2656
|
Args:
|
|
2634
2657
|
*args: Positional arguments from the documented upload signature.
|
|
@@ -2640,8 +2663,8 @@ class AsyncShotgun:
|
|
|
2640
2663
|
Raises:
|
|
2641
2664
|
TypeError: If arguments do not match the documented signature.
|
|
2642
2665
|
ShotgunError: If the file or an upload response is invalid, an RPC
|
|
2643
|
-
fault or terminal transport failure occurs, or the
|
|
2644
|
-
form
|
|
2666
|
+
fault or terminal transport failure occurs, or the server
|
|
2667
|
+
requires legacy form uploads.
|
|
2645
2668
|
ProtocolError: If an upload endpoint returns an HTTP error.
|
|
2646
2669
|
ValueError: If authenticated HTTP violates the configured origin
|
|
2647
2670
|
policy.
|
|
@@ -2673,6 +2696,9 @@ class AsyncShotgun:
|
|
|
2673
2696
|
) -> int:
|
|
2674
2697
|
"""Upload a filmstrip thumbnail through `upload`.
|
|
2675
2698
|
|
|
2699
|
+
Servers requiring legacy form uploads are rejected before any upload
|
|
2700
|
+
request is sent.
|
|
2701
|
+
|
|
2676
2702
|
Args:
|
|
2677
2703
|
entity_type: Entity type receiving the thumbnail.
|
|
2678
2704
|
entity_id: Numeric identifier of the receiving entity.
|
|
@@ -2685,7 +2711,8 @@ class AsyncShotgun:
|
|
|
2685
2711
|
Raises:
|
|
2686
2712
|
TypeError: If forwarded arguments do not match `upload`.
|
|
2687
2713
|
ShotgunError: If an RPC fault or terminal transport failure occurs,
|
|
2688
|
-
or if the file, upload response, or transport fails
|
|
2714
|
+
or if the file, upload response, or transport fails, or the
|
|
2715
|
+
server requires legacy form uploads.
|
|
2689
2716
|
ProtocolError: If an upload endpoint returns an HTTP error.
|
|
2690
2717
|
ValueError: If authenticated HTTP violates the configured origin
|
|
2691
2718
|
policy.
|
|
@@ -2707,6 +2734,9 @@ class AsyncShotgun:
|
|
|
2707
2734
|
) -> int:
|
|
2708
2735
|
"""Upload a static thumbnail through `upload`.
|
|
2709
2736
|
|
|
2737
|
+
Servers requiring legacy form uploads are rejected before any upload
|
|
2738
|
+
request is sent.
|
|
2739
|
+
|
|
2710
2740
|
Args:
|
|
2711
2741
|
entity_type: Entity type receiving the thumbnail.
|
|
2712
2742
|
entity_id: Numeric identifier of the receiving entity.
|
|
@@ -2719,7 +2749,8 @@ class AsyncShotgun:
|
|
|
2719
2749
|
Raises:
|
|
2720
2750
|
TypeError: If forwarded arguments do not match `upload`.
|
|
2721
2751
|
ShotgunError: If an RPC fault or terminal transport failure occurs,
|
|
2722
|
-
or if the file, upload response, or transport fails
|
|
2752
|
+
or if the file, upload response, or transport fails, or the
|
|
2753
|
+
server requires legacy form uploads.
|
|
2723
2754
|
ProtocolError: If an upload endpoint returns an HTTP error.
|
|
2724
2755
|
ValueError: If authenticated HTTP violates the configured origin
|
|
2725
2756
|
policy.
|
|
@@ -2735,28 +2766,40 @@ class AsyncShotgun:
|
|
|
2735
2766
|
async def user_subscriptions_create(self, users: list[dict[str, Any]]) -> bool:
|
|
2736
2767
|
"""Assign subscriptions to users.
|
|
2737
2768
|
|
|
2769
|
+
The server accepts this call from scripts and from human users with
|
|
2770
|
+
permission to manage subscriptions, such as members of the Admin
|
|
2771
|
+
permission group. It refuses other human users.
|
|
2772
|
+
|
|
2738
2773
|
Args:
|
|
2739
|
-
users: Subscription dictionaries
|
|
2774
|
+
users: Subscription dictionaries with a string or integer
|
|
2775
|
+
`humanUserId`; integers become decimal string keys and booleans
|
|
2776
|
+
are not accepted. Each user may appear only once.
|
|
2777
|
+
`subscription` is `None`, a string, or a list of strings.
|
|
2778
|
+
Lists are copied in order. Other entry keys are ignored.
|
|
2740
2779
|
|
|
2741
2780
|
Returns:
|
|
2742
|
-
|
|
2781
|
+
`True` when every per-user report is `None`, meaning the server
|
|
2782
|
+
reported no problem; `False` when any user has a non-`None` report.
|
|
2743
2783
|
|
|
2744
2784
|
Raises:
|
|
2745
2785
|
ShotgunError: If an RPC fault or terminal transport failure occurs,
|
|
2746
|
-
or if
|
|
2786
|
+
or if `users` contains invalid or duplicate entries, or the
|
|
2787
|
+
server result is not a mapping with string keys.
|
|
2747
2788
|
ProtocolError: If a server request returns an HTTP error.
|
|
2748
2789
|
ValueError: If authenticated HTTP violates the configured origin
|
|
2749
2790
|
policy.
|
|
2750
2791
|
"""
|
|
2751
2792
|
params = _methods.build_user_subscriptions_create_params(users)
|
|
2752
2793
|
result = await self._call('user_subscriptions_create', params)
|
|
2753
|
-
return
|
|
2794
|
+
return _methods.require_user_subscriptions_create_result(result)
|
|
2754
2795
|
|
|
2755
2796
|
async def user_subscriptions_read(self) -> list[dict[str, object]]:
|
|
2756
|
-
"""List
|
|
2797
|
+
"""List user subscriptions in server order.
|
|
2757
2798
|
|
|
2758
2799
|
Returns:
|
|
2759
|
-
|
|
2800
|
+
Subscription entries in server order, each with an unchanged string
|
|
2801
|
+
`humanUserId` and a `subscription` of `None`, a string, or a copied
|
|
2802
|
+
list of strings.
|
|
2760
2803
|
|
|
2761
2804
|
Raises:
|
|
2762
2805
|
ShotgunError: If an RPC fault or terminal transport failure occurs,
|
|
@@ -2766,7 +2809,7 @@ class AsyncShotgun:
|
|
|
2766
2809
|
policy.
|
|
2767
2810
|
"""
|
|
2768
2811
|
result = await self._call('user_subscriptions_read', None)
|
|
2769
|
-
return _methods.
|
|
2812
|
+
return _methods.require_user_subscriptions_result(result)
|
|
2770
2813
|
|
|
2771
2814
|
async def work_schedule_read(
|
|
2772
2815
|
self,
|