sg-python-api 0.1.0__tar.gz → 0.1.1__tar.gz
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 → sg_python_api-0.1.1}/COMPATIBILITY.md +2 -7
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/PKG-INFO +14 -27
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/README.md +1 -14
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/docs/benchmarks.md +27 -26
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/docs/development.md +2 -3
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/docs/migration-guide.md +3 -9
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/pyproject.toml +1 -1
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/scripts/_conformance_setup.py +0 -8
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/scripts/_sdist_contract.py +1 -1
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/scripts/run_installed_tests.py +1 -1
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/_async_client.py +79 -58
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/_async_driver.py +2 -14
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/_client.py +75 -60
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/_config.py +2 -10
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/_driver.py +4 -18
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/_files.py +44 -5
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/_methods.py +11 -80
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/_version.py +1 -1
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/client/test_async.py +1 -1
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/client/test_crud.py +1 -3
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/client/test_schema.py +23 -269
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/client/test_sync.py +1 -1
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/files/test_async.py +120 -1
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/files/test_uploads.py +153 -3
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/live/test_async.py +45 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/live/test_roundtrip.py +47 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/test_config.py +2 -2
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/test_init.py +1 -1
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/test_parity.py +12 -27
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/tooling/test_artifact_evidence.py +5 -5
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/tooling/test_benchmark.py +10 -10
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/tooling/test_conformance_setup.py +9 -31
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/tooling/test_run_conformance.py +40 -32
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/tooling/test_run_installed_tests.py +3 -3
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/tooling/test_validate_artifacts.py +13 -13
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/transport/test_async_driver.py +2 -6
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/transport/test_driver.py +20 -29
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/.gitignore +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/LICENSE +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/Makefile +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/docs/testing.md +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/examples/async_client.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/examples/sync_client.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/scripts/_artifact_evidence.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/scripts/_conformance_runtime.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/scripts/benchmark.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/scripts/bootstrap_test_site.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/scripts/probe_wire.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/scripts/run_conformance.sh +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/scripts/validate_artifacts.sh +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/__init__.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/_async_httpx2.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/_async_transport.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/_capabilities.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/_crud.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/_errors.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/_execution.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/_protocol.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/_sentinel.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/_sg_timezone.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/_signatures.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/_transport.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/lib/__init__.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/lib/mockgun/__init__.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/lib/mockgun/_async.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/lib/mockgun/_mockgun.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/lib/sgtimezone.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/py.typed +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/src/shotgun_api3/shotgun.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/__init__.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/_git.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/_loopback.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/_pyright.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/_required_mode.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/_transports.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/client/__init__.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/client/test_activity.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/client/test_auth_methods.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/client/test_filters.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/client/test_misc_methods.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/client/test_nav.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/client/test_summarize_search.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/conftest.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/files/__init__.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/files/test_cookie_handler.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/files/test_downloads.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/files/test_multipart.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/files/test_upload_routing.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/fixtures/activity_stream_read.json +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/fixtures/batch.json +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/fixtures/create.json +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/fixtures/fault_bad_auth.json +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/fixtures/following.json +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/fixtures/get_session_token.json +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/fixtures/info.json +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/fixtures/nav_expand.json +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/fixtures/preferences_read.json +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/fixtures/read.json +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/fixtures/schema_entity_read.json +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/fixtures/schema_read.json +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/fixtures/summarize.json +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/fixtures/text_search.json +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/fixtures/update_project_last_accessed.json +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/fixtures/work_schedule_read.json +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/lib/__init__.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/lib/conftest.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/lib/test_mockgun_async.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/lib/test_mockgun_crud.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/lib/test_mockgun_find.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/lib/test_mockgun_schema.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/lib/test_sgtimezone.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/live/__init__.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/live/conftest.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/test_datetimes.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/test_errors.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/test_examples.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/test_project_metadata.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/test_signature_parity.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/tooling/__init__.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/tooling/_wire_replay.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/tooling/test_conformance_runtime.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/tooling/test_required_mode.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/tooling/test_wire_fixtures.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/transport/__init__.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/transport/test_abort.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/transport/test_async.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/transport/test_async_httpx2.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/transport/test_async_prefetch.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/transport/test_prefetch.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/transport/test_protocol.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/transport/test_retry_policy.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/transport/test_streaming.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/transport/test_sync.py +0 -0
- {sg_python_api-0.1.0 → sg_python_api-0.1.1}/tests/transport/test_urllib3.py +0 -0
|
@@ -168,13 +168,8 @@ import logging
|
|
|
168
168
|
logging.getLogger('httpx2').setLevel(logging.WARNING)
|
|
169
169
|
```
|
|
170
170
|
|
|
171
|
-
Compatibility warnings use stable codes and fixed messages
|
|
172
|
-
|
|
173
|
-
| Code | Emitted when |
|
|
174
|
-
| ------------------------------- | --------------------------------------------------------------------------------------- |
|
|
175
|
-
| `deprecated-entity-types-alias` | The application calls `entity_types()`, the deprecated alias of `schema_entity_read()`. |
|
|
176
|
-
| `deprecated-schema-alias` | The application calls `schema()`, the deprecated alias of `schema_field_read()`. |
|
|
177
|
-
| `legacy-infinite-timeout` | An operation runs with `sg.config.timeout_secs` set to `None`. |
|
|
171
|
+
Compatibility warnings use stable codes and fixed messages. The client emits one code,
|
|
172
|
+
`legacy-infinite-timeout`, when an operation runs with `sg.config.timeout_secs` set to `None`.
|
|
178
173
|
|
|
179
174
|
### Callback threads and failures
|
|
180
175
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: sg-python-api
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
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
|
|
@@ -45,8 +45,8 @@ This documentation uses SG for Flow Production Tracking, formerly named Shotgun
|
|
|
45
45
|
|
|
46
46
|
sg-python-api is an independent implementation of the documented API of Autodesk's Python client
|
|
47
47
|
`3.10.2`. 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.
|
|
49
|
-
through the switch, and the [compatibility reference](https://github.com/dactylo/sg-python-api/blob/v0.1.
|
|
48
|
+
site before replacing its production client. The [migration guide](https://github.com/dactylo/sg-python-api/blob/v0.1.1/docs/migration-guide.md) walks
|
|
49
|
+
through the switch, and the [compatibility reference](https://github.com/dactylo/sg-python-api/blob/v0.1.1/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.1/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.1/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.1/docs/migration-guide.md) |
|
|
141
|
+
| Check what behaves differently from Autodesk's client | [Compatibility](https://github.com/dactylo/sg-python-api/blob/v0.1.1/COMPATIBILITY.md) |
|
|
142
|
+
| Tune pooling and page prefetch, or observe requests | [Configuration extensions](https://github.com/dactylo/sg-python-api/blob/v0.1.1/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.1/docs/testing.md) |
|
|
144
|
+
| Compare measured latency and transfer memory | [Benchmarks](https://github.com/dactylo/sg-python-api/blob/v0.1.1/docs/benchmarks.md) |
|
|
145
|
+
| See changes by version | [Changelog](https://github.com/dactylo/sg-python-api/blob/v0.1.1/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.1/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.1/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.
|
|
@@ -33,14 +33,7 @@ requests to a remote site require HTTPS.
|
|
|
33
33
|
exactly one of them in a Python environment. If the official client is already installed, follow
|
|
34
34
|
the [migration steps](docs/migration-guide.md#install-the-replacement) to replace it.
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
your application:
|
|
38
|
-
|
|
39
|
-
```sh
|
|
40
|
-
python -m pip install sg-python-api
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
To install from a checkout instead, run:
|
|
36
|
+
From a checkout, install into the Python environment that runs your application:
|
|
44
37
|
|
|
45
38
|
```sh
|
|
46
39
|
python -m pip install .
|
|
@@ -50,12 +43,6 @@ The base installation provides the synchronous `Shotgun` client and both `mockgu
|
|
|
50
43
|
use the native asynchronous client, `AsyncShotgun`, install the `async` extra, which adds the
|
|
51
44
|
`httpx2` HTTP library:
|
|
52
45
|
|
|
53
|
-
```sh
|
|
54
|
-
python -m pip install 'sg-python-api[async]'
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
From a checkout, use:
|
|
58
|
-
|
|
59
46
|
```sh
|
|
60
47
|
python -m pip install '.[async]'
|
|
61
48
|
```
|
|
@@ -7,9 +7,10 @@ on your site. If you have not tried the client yet, start with the
|
|
|
7
7
|
|
|
8
8
|
## What the results show
|
|
9
9
|
|
|
10
|
-
- **Latency was mixed.** In these samples,
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
- **Latency was mixed.** In these samples, all three upload routes had lower medians with
|
|
11
|
+
sg-python-api, cold and warm, and so did warm downloads. Cold medians were higher for writes,
|
|
12
|
+
schema reads, summaries, and the four-concurrent-read comparison. Warm medians were similar or
|
|
13
|
+
lower except for the encode-heavy batch.
|
|
13
14
|
- **Transfer memory was lower in the measured workloads.** sg-python-api's peak process memory grew
|
|
14
15
|
less during the measured upload and download. That observation also depends on payload shape and
|
|
15
16
|
runtime.
|
|
@@ -39,7 +40,7 @@ In the tables below, "replacement" means sg-python-api and "official" means Auto
|
|
|
39
40
|
|
|
40
41
|
| Setting | Value |
|
|
41
42
|
| --------------------------- | ----------------------------------------------------------------------- |
|
|
42
|
-
| Replacement package version | `0.
|
|
43
|
+
| Replacement package version | `0.1.1` |
|
|
43
44
|
| Autodesk client version | `3.10.2` |
|
|
44
45
|
| Python | `3.14.6` |
|
|
45
46
|
| Platform | macOS, arm64 |
|
|
@@ -55,26 +56,26 @@ estimate a reliable tail-latency distribution.
|
|
|
55
56
|
|
|
56
57
|
| Operation | Replacement cold | Official cold | Replacement warm | Official warm |
|
|
57
58
|
| ----------------------------------- | ---------------: | ------------: | ---------------: | ------------: |
|
|
58
|
-
| First script-authenticated request |
|
|
59
|
-
| Batch |
|
|
60
|
-
| Create |
|
|
61
|
-
| Delete |
|
|
62
|
-
| Download |
|
|
63
|
-
| Medium query |
|
|
64
|
-
| Find one |
|
|
65
|
-
| Paged query |
|
|
66
|
-
| Small query |
|
|
67
|
-
| Four concurrent reads |
|
|
68
|
-
| Decode-heavy read |
|
|
69
|
-
| Encode-heavy batch |
|
|
70
|
-
| Entity schema |
|
|
71
|
-
| Field schema |
|
|
72
|
-
| First session-authenticated request |
|
|
73
|
-
| Summarize |
|
|
74
|
-
| Update |
|
|
75
|
-
| Direct upload |
|
|
76
|
-
| Generic upload |
|
|
77
|
-
| Multipart upload |
|
|
59
|
+
| First script-authenticated request | 366.6 | 358.9 | 119.7 | 124.7 |
|
|
60
|
+
| Batch | 410.7 | 309.8 | 160.5 | 178.6 |
|
|
61
|
+
| Create | 407.0 | 328.3 | 175.0 | 172.1 |
|
|
62
|
+
| Delete | 456.8 | 362.4 | 193.0 | 233.5 |
|
|
63
|
+
| Download | 602.2 | 605.4 | 336.3 | 377.0 |
|
|
64
|
+
| Medium query | 362.6 | 371.6 | 120.7 | 126.1 |
|
|
65
|
+
| Find one | 354.3 | 371.3 | 128.6 | 133.4 |
|
|
66
|
+
| Paged query | 490.2 | 484.0 | 263.8 | 254.0 |
|
|
67
|
+
| Small query | 354.1 | 380.7 | 125.6 | 133.8 |
|
|
68
|
+
| Four concurrent reads | 520.6 | 377.5 | 129.6 | 131.1 |
|
|
69
|
+
| Decode-heavy read | 361.0 | 365.9 | 129.9 | 138.9 |
|
|
70
|
+
| Encode-heavy batch | 993.3 | 790.8 | 665.0 | 565.4 |
|
|
71
|
+
| Entity schema | 346.5 | 276.7 | 117.7 | 113.9 |
|
|
72
|
+
| Field schema | 371.4 | 303.3 | 141.2 | 146.3 |
|
|
73
|
+
| First session-authenticated request | 489.3 | 477.0 | 116.3 | 127.6 |
|
|
74
|
+
| Summarize | 370.7 | 282.8 | 122.2 | 133.5 |
|
|
75
|
+
| Update | 394.6 | 298.1 | 163.5 | 157.2 |
|
|
76
|
+
| Direct upload | 982.0 | 1183.9 | 652.6 | 950.1 |
|
|
77
|
+
| Generic upload | 797.1 | 1128.5 | 596.2 | 814.0 |
|
|
78
|
+
| Multipart upload | 2389.0 | 3118.5 | 2163.7 | 2745.0 |
|
|
78
79
|
|
|
79
80
|
## Transfer memory
|
|
80
81
|
|
|
@@ -84,8 +85,8 @@ memory use or individual Python allocations.
|
|
|
84
85
|
|
|
85
86
|
| Workload | Replacement peak increase | Official peak increase |
|
|
86
87
|
| -------- | ------------------------: | ---------------------: |
|
|
87
|
-
| Download | 3.
|
|
88
|
-
| Upload |
|
|
88
|
+
| Download | 3.34 MiB | 7.31 MiB |
|
|
89
|
+
| Upload | 1.95 MiB | 24.70 MiB |
|
|
89
90
|
|
|
90
91
|
The upload measurement used the multipart route. Download memory uses a fresh download-only process
|
|
91
92
|
after setup so earlier work does not dominate the process's high-water mark.
|
|
@@ -137,9 +137,8 @@ API tests without the official client's legacy transport. Individual tests tied
|
|
|
137
137
|
private methods, bundled `httplib2`, or unsupported server versions are explicitly skipped. Their
|
|
138
138
|
exact names and reasons are recorded in `scripts/_conformance_setup.py`; unexpected imports still
|
|
139
139
|
fail. Four tests use a reduced setup because their assertions do not require the legacy transport
|
|
140
|
-
mocks.
|
|
141
|
-
|
|
142
|
-
without requiring Autodesk's exact message text.
|
|
140
|
+
mocks. Two test methods have explicit expectation adaptations: invalid export arguments must raise
|
|
141
|
+
`ShotgunError` without requiring Autodesk's exact message text.
|
|
143
142
|
|
|
144
143
|
The runtime fixtures snapshot and restore the existing user fields, custom schema and visibility,
|
|
145
144
|
and schedule exceptions changed by the tests. The two schema tests use unique field names on each
|
|
@@ -26,21 +26,15 @@ these:
|
|
|
26
26
|
|
|
27
27
|
Use your application's package manager to remove `shotgun-api3` and install `sg-python-api`. Both
|
|
28
28
|
provide `shotgun_api3`, so they cannot coexist in one environment. In a pip-managed environment,
|
|
29
|
-
|
|
29
|
+
run these commands from a checkout of `sg-python-api`:
|
|
30
30
|
|
|
31
31
|
```sh
|
|
32
32
|
python -m pip uninstall shotgun-api3
|
|
33
|
-
python -m pip install sg-python-api
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
To install from a checkout instead, run the second command there as:
|
|
37
|
-
|
|
38
|
-
```sh
|
|
39
33
|
python -m pip install .
|
|
40
34
|
```
|
|
41
35
|
|
|
42
|
-
When the application needs native async support,
|
|
43
|
-
|
|
36
|
+
When the application needs native async support, run `python -m pip install '.[async]'` instead of
|
|
37
|
+
the second command. Existing `import shotgun_api3` statements stay as they are.
|
|
44
38
|
|
|
45
39
|
Next, [confirm which client loads](testing.md#verify-the-import-target) and run the
|
|
46
40
|
[read-only smoke test](testing.md#run-a-read-only-smoke-test) with a test-site credential. A
|
|
@@ -10,7 +10,7 @@ requires = [ "editables~=0.3", "hatch-fancy-pypi-readme>=25.1", "hatchling>=1.27
|
|
|
10
10
|
# ==========================================================
|
|
11
11
|
[project]
|
|
12
12
|
name = "sg-python-api"
|
|
13
|
-
version = "0.1.
|
|
13
|
+
version = "0.1.1"
|
|
14
14
|
description = "Python client for Autodesk Flow Production Tracking"
|
|
15
15
|
keywords = [ "api", "flow-production-tracking", "shotgrid", "shotgun", "shotgun-api3" ]
|
|
16
16
|
license = "MIT"
|
|
@@ -197,14 +197,6 @@ _EXPECTATIONS = {
|
|
|
197
197
|
"self.assertRaises(shotgun_api3.ShotgunError, self.sg.export_page, None, 'csv', "
|
|
198
198
|
"layout_name='Conformance')\n"
|
|
199
199
|
),
|
|
200
|
-
'TestShotgunApi.test_deprecated_functions': (
|
|
201
|
-
'with self.assertWarns(DeprecationWarning):\n'
|
|
202
|
-
' entity_schema = self.sg.entity_types()\n'
|
|
203
|
-
'self.assertEqual(entity_schema, self.sg.schema_entity_read())\n'
|
|
204
|
-
'with self.assertWarns(DeprecationWarning):\n'
|
|
205
|
-
" field_schema = self.sg.schema('Asset')\n"
|
|
206
|
-
"self.assertEqual(field_schema, self.sg.schema_field_read('Asset'))\n"
|
|
207
|
-
),
|
|
208
200
|
}
|
|
209
201
|
_SCHEMA_INPUTS = {
|
|
210
202
|
'TestFind.test_zero_is_not_none': (
|
|
@@ -22,7 +22,7 @@ if TYPE_CHECKING:
|
|
|
22
22
|
_ARTIFACT_ARGUMENT_COUNT = 6
|
|
23
23
|
_COMMAND_ARGUMENT_COUNT = 3
|
|
24
24
|
_DIRECT_DOC_PART_COUNT = 2
|
|
25
|
-
_EXPECTED_VERSION = '0.1.
|
|
25
|
+
_EXPECTED_VERSION = '0.1.1'
|
|
26
26
|
_REGULAR_MEMBER_TYPES = frozenset({tarfile.AREGTYPE, tarfile.REGTYPE})
|
|
27
27
|
_ROOT_SOURCE_FILES = frozenset(
|
|
28
28
|
{
|
|
@@ -144,7 +144,7 @@ _EXPECTED_URLS = {
|
|
|
144
144
|
'Issues': 'https://github.com/dactylo/sg-python-api/issues',
|
|
145
145
|
'Repository': 'https://github.com/dactylo/sg-python-api',
|
|
146
146
|
}
|
|
147
|
-
_EXPECTED_VERSION = '0.1.
|
|
147
|
+
_EXPECTED_VERSION = '0.1.1'
|
|
148
148
|
_PACKAGE_NAME = 'shotgun_api3'
|
|
149
149
|
_Mode = Literal['async', 'base']
|
|
150
150
|
|
|
@@ -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,
|
|
@@ -288,7 +287,6 @@ class _InvocationOptions:
|
|
|
288
287
|
"""Collect non-payload controls for one client invocation."""
|
|
289
288
|
|
|
290
289
|
auth_spec: _protocol.AuthSpec | None = None
|
|
291
|
-
compatibility_warning_codes: tuple[CompatibilityWarningCode, ...] = ()
|
|
292
290
|
include_auth: bool = True
|
|
293
291
|
logical_method_name: str | None = None
|
|
294
292
|
|
|
@@ -523,7 +521,6 @@ class AsyncShotgun:
|
|
|
523
521
|
outbound,
|
|
524
522
|
context,
|
|
525
523
|
include_auth=invocation.options.include_auth,
|
|
526
|
-
compatibility_warning_codes=invocation.options.compatibility_warning_codes,
|
|
527
524
|
_logical_method_name=invocation.options.logical_method_name,
|
|
528
525
|
)
|
|
529
526
|
return _protocol.transform_inbound(result, context.convert_datetimes_to_utc)
|
|
@@ -1220,6 +1217,28 @@ class AsyncShotgun:
|
|
|
1220
1217
|
await self._upload_direct(driver, context, prepared, upload_info)
|
|
1221
1218
|
return await self._upload_link(driver, context, prepared, upload_info)
|
|
1222
1219
|
|
|
1220
|
+
async def _upload_thumbnails_after_write(
|
|
1221
|
+
self,
|
|
1222
|
+
entity_type: str,
|
|
1223
|
+
entity_id: int,
|
|
1224
|
+
thumbnails: dict[str, object],
|
|
1225
|
+
result: dict[str, object],
|
|
1226
|
+
) -> dict[str, object]:
|
|
1227
|
+
"""Upload separated thumbnail paths and merge their current field values."""
|
|
1228
|
+
if not thumbnails:
|
|
1229
|
+
return result
|
|
1230
|
+
for field_name, path in thumbnails.items():
|
|
1231
|
+
upload = (
|
|
1232
|
+
self.upload_filmstrip_thumbnail
|
|
1233
|
+
if field_name == 'filmstrip_image'
|
|
1234
|
+
else self.upload_thumbnail
|
|
1235
|
+
)
|
|
1236
|
+
await upload(entity_type, entity_id, cast('str', path))
|
|
1237
|
+
current = await self.find_one(entity_type, [['id', 'is', entity_id]], list(thumbnails))
|
|
1238
|
+
if current is not None:
|
|
1239
|
+
result.update({field_name: current.get(field_name) for field_name in thumbnails})
|
|
1240
|
+
return result
|
|
1241
|
+
|
|
1223
1242
|
@overload
|
|
1224
1243
|
async def activity_stream_read(self, entity_type: Never) -> dict[str, object]: ...
|
|
1225
1244
|
|
|
@@ -1520,6 +1539,10 @@ class AsyncShotgun:
|
|
|
1520
1539
|
) -> dict[str, object]:
|
|
1521
1540
|
"""Create an entity with the supplied field values.
|
|
1522
1541
|
|
|
1542
|
+
Non-empty `image` and `filmstrip_image` values are file paths. They are
|
|
1543
|
+
uploaded as thumbnails after the entity is created, and the result
|
|
1544
|
+
includes their current field values.
|
|
1545
|
+
|
|
1523
1546
|
Args:
|
|
1524
1547
|
entity_type: Entity type to create.
|
|
1525
1548
|
data: Field values for the new entity.
|
|
@@ -1530,14 +1553,22 @@ class AsyncShotgun:
|
|
|
1530
1553
|
|
|
1531
1554
|
Raises:
|
|
1532
1555
|
ShotgunError: If an RPC fault or terminal transport failure occurs,
|
|
1533
|
-
|
|
1534
|
-
result is invalid
|
|
1556
|
+
if `data`, its field names, `return_fields`, or the server
|
|
1557
|
+
result is invalid, or if a thumbnail path is not a nonempty
|
|
1558
|
+
file. A thumbnail failure occurs after the entity is created.
|
|
1535
1559
|
ProtocolError: If a server request returns an HTTP error.
|
|
1536
1560
|
ValueError: If authenticated HTTP violates the configured origin
|
|
1537
1561
|
policy.
|
|
1538
1562
|
"""
|
|
1539
|
-
|
|
1540
|
-
|
|
1563
|
+
field_data, thumbnails = _files.split_thumbnail_uploads(data, keep_image_none=False)
|
|
1564
|
+
params = _crud.build_create_params(entity_type, field_data, return_fields)
|
|
1565
|
+
result = _crud.require_dictionary_result(await self._call('create', params), 'create')
|
|
1566
|
+
if not thumbnails:
|
|
1567
|
+
return result
|
|
1568
|
+
entity_id = _crud.require_entity_id(result.get('id'), 'create did not return an entity id')
|
|
1569
|
+
return await self._upload_thumbnails_after_write(
|
|
1570
|
+
entity_type, entity_id, thumbnails, result
|
|
1571
|
+
)
|
|
1541
1572
|
|
|
1542
1573
|
async def delete(self, entity_type: str, entity_id: int) -> bool:
|
|
1543
1574
|
"""Retire an entity.
|
|
@@ -1642,6 +1673,15 @@ class AsyncShotgun:
|
|
|
1642
1673
|
except (TransportError, _errors.ProtocolError, OSError):
|
|
1643
1674
|
raise _errors.ShotgunFileDownloadError('attachment download failed') from None
|
|
1644
1675
|
|
|
1676
|
+
async def entity_types(self) -> Never:
|
|
1677
|
+
"""Reject the deprecated alias of `schema_entity_read()` without I/O.
|
|
1678
|
+
|
|
1679
|
+
Raises:
|
|
1680
|
+
ShotgunError: Always, naming `schema_entity_read()` as the
|
|
1681
|
+
replacement.
|
|
1682
|
+
"""
|
|
1683
|
+
raise _methods.entity_types_alias_error()
|
|
1684
|
+
|
|
1645
1685
|
@overload
|
|
1646
1686
|
async def export_page(
|
|
1647
1687
|
self,
|
|
@@ -2085,6 +2125,18 @@ class AsyncShotgun:
|
|
|
2085
2125
|
params = _crud.build_entity_action_params(entity_type, entity_id)
|
|
2086
2126
|
return _crud.require_boolean_result(await self._call('revive', params), 'revive')
|
|
2087
2127
|
|
|
2128
|
+
async def schema(self, entity_type: str) -> Never:
|
|
2129
|
+
"""Reject the deprecated alias of `schema_field_read()` without I/O.
|
|
2130
|
+
|
|
2131
|
+
Args:
|
|
2132
|
+
entity_type: Entity type named in the replacement suggestion.
|
|
2133
|
+
|
|
2134
|
+
Raises:
|
|
2135
|
+
ShotgunError: Always, naming the equivalent `schema_field_read()`
|
|
2136
|
+
call.
|
|
2137
|
+
"""
|
|
2138
|
+
raise _methods.schema_alias_error(entity_type)
|
|
2139
|
+
|
|
2088
2140
|
async def schema_entity_read(
|
|
2089
2141
|
self,
|
|
2090
2142
|
project_entity: dict[str, Any] | None = None,
|
|
@@ -2104,34 +2156,12 @@ class AsyncShotgun:
|
|
|
2104
2156
|
ValueError: If authenticated HTTP violates the configured origin
|
|
2105
2157
|
policy.
|
|
2106
2158
|
"""
|
|
2107
|
-
warnings_codes = _methods.consume_compatibility_warnings(
|
|
2108
|
-
_methods.SCHEMA_ENTITY_READ_WARNINGS,
|
|
2109
|
-
self,
|
|
2110
|
-
)
|
|
2111
2159
|
result = await self._call(
|
|
2112
2160
|
'schema_entity_read',
|
|
2113
2161
|
_methods.build_schema_entity_read_params(project_entity),
|
|
2114
|
-
_InvocationOptions(compatibility_warning_codes=warnings_codes),
|
|
2115
2162
|
)
|
|
2116
2163
|
return _crud.require_dictionary_result(result, 'schema_entity_read')
|
|
2117
2164
|
|
|
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
2165
|
async def schema_field_create(
|
|
2136
2166
|
self,
|
|
2137
2167
|
entity_type: str,
|
|
@@ -2210,10 +2240,6 @@ class AsyncShotgun:
|
|
|
2210
2240
|
ValueError: If authenticated HTTP violates the configured origin
|
|
2211
2241
|
policy.
|
|
2212
2242
|
"""
|
|
2213
|
-
warning_codes = _methods.consume_compatibility_warnings(
|
|
2214
|
-
_methods.SCHEMA_FIELD_READ_WARNINGS,
|
|
2215
|
-
self,
|
|
2216
|
-
)
|
|
2217
2243
|
result = await self._call(
|
|
2218
2244
|
'schema_field_read',
|
|
2219
2245
|
_methods.build_schema_field_read_params(
|
|
@@ -2221,30 +2247,9 @@ class AsyncShotgun:
|
|
|
2221
2247
|
field_name,
|
|
2222
2248
|
project_entity,
|
|
2223
2249
|
),
|
|
2224
|
-
_InvocationOptions(compatibility_warning_codes=warning_codes),
|
|
2225
2250
|
)
|
|
2226
2251
|
return _crud.require_dictionary_result(result, 'schema_field_read')
|
|
2227
2252
|
|
|
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
2253
|
async def schema_field_update(
|
|
2249
2254
|
self,
|
|
2250
2255
|
entity_type: str,
|
|
@@ -2559,6 +2564,12 @@ class AsyncShotgun:
|
|
|
2559
2564
|
) -> dict[str, object]:
|
|
2560
2565
|
"""Update fields on an existing entity.
|
|
2561
2566
|
|
|
2567
|
+
Non-empty `image` and `filmstrip_image` values are file paths. They are
|
|
2568
|
+
uploaded as thumbnails after the other fields are updated, and the
|
|
2569
|
+
result includes their current field values. An `image` of `None` clears
|
|
2570
|
+
both thumbnails. When no other fields remain, no update request is sent
|
|
2571
|
+
and the result contains only `id` and `type`.
|
|
2572
|
+
|
|
2562
2573
|
Args:
|
|
2563
2574
|
entity_type: Entity type to update.
|
|
2564
2575
|
entity_id: Numeric entity identifier.
|
|
@@ -2570,19 +2581,29 @@ class AsyncShotgun:
|
|
|
2570
2581
|
|
|
2571
2582
|
Raises:
|
|
2572
2583
|
ShotgunError: If an RPC fault or terminal transport failure occurs,
|
|
2573
|
-
|
|
2574
|
-
|
|
2584
|
+
if `data`, its field names, `multi_entity_update_modes`, or the
|
|
2585
|
+
server result is invalid, or if a thumbnail path is not a
|
|
2586
|
+
nonempty file. A thumbnail failure occurs after the update.
|
|
2575
2587
|
ProtocolError: If a server request returns an HTTP error.
|
|
2576
2588
|
ValueError: If authenticated HTTP violates the configured origin
|
|
2577
2589
|
policy.
|
|
2578
2590
|
"""
|
|
2591
|
+
field_data, thumbnails = _files.split_thumbnail_uploads(data, keep_image_none=True)
|
|
2579
2592
|
params = _crud.build_update_params(
|
|
2580
2593
|
entity_type,
|
|
2581
2594
|
entity_id,
|
|
2582
|
-
|
|
2595
|
+
field_data,
|
|
2583
2596
|
multi_entity_update_modes,
|
|
2584
2597
|
)
|
|
2585
|
-
|
|
2598
|
+
result: dict[str, object] = {'id': entity_id, 'type': entity_type}
|
|
2599
|
+
if params['fields']:
|
|
2600
|
+
result = _crud.require_dictionary_result(
|
|
2601
|
+
await self._call('update', params),
|
|
2602
|
+
'update',
|
|
2603
|
+
)
|
|
2604
|
+
return await self._upload_thumbnails_after_write(
|
|
2605
|
+
entity_type, entity_id, thumbnails, result
|
|
2606
|
+
)
|
|
2586
2607
|
|
|
2587
2608
|
async def update_project_last_accessed(
|
|
2588
2609
|
self,
|
|
@@ -15,7 +15,6 @@ from typing import Protocol, TypeVar, cast
|
|
|
15
15
|
from . import _protocol, _transport
|
|
16
16
|
from ._async_transport import AsyncTransport
|
|
17
17
|
from ._config import (
|
|
18
|
-
CompatibilityWarningCode,
|
|
19
18
|
EventRoute,
|
|
20
19
|
ObserverCallback,
|
|
21
20
|
Outcome,
|
|
@@ -200,14 +199,11 @@ class AsyncExecutionOptions:
|
|
|
200
199
|
"""Control async executor transport choreography.
|
|
201
200
|
|
|
202
201
|
Attributes:
|
|
203
|
-
compatibility_warning_codes: Compatibility warnings emitted before
|
|
204
|
-
attempts.
|
|
205
202
|
logical_method_name: Optional observer-facing operation name.
|
|
206
203
|
redirect_factory: Optional request factory for redirect responses.
|
|
207
204
|
streaming: Whether the response body is consumed as a stream.
|
|
208
205
|
"""
|
|
209
206
|
|
|
210
|
-
compatibility_warning_codes: tuple[CompatibilityWarningCode, ...] = ()
|
|
211
207
|
logical_method_name: str | None = None
|
|
212
208
|
redirect_factory: Callable[['AsyncLiveResponse'], TransportRequest] | None = None
|
|
213
209
|
streaming: bool = False
|
|
@@ -486,10 +482,7 @@ class AsyncDriver:
|
|
|
486
482
|
consumption, or cleanup fails.
|
|
487
483
|
"""
|
|
488
484
|
execution_options = options or AsyncExecutionOptions()
|
|
489
|
-
for event in compatibility_warning_events(
|
|
490
|
-
execution_options.compatibility_warning_codes,
|
|
491
|
-
context.timeout,
|
|
492
|
-
):
|
|
485
|
+
for event in compatibility_warning_events(context.timeout):
|
|
493
486
|
notify_observer(context.on_compatibility_warning, event)
|
|
494
487
|
route = event_route(operation)
|
|
495
488
|
self._transport.checkout()
|
|
@@ -590,7 +583,6 @@ class AsyncDriver:
|
|
|
590
583
|
params: object,
|
|
591
584
|
context: RequestContext,
|
|
592
585
|
include_auth: bool = True,
|
|
593
|
-
compatibility_warning_codes: tuple[CompatibilityWarningCode, ...] = (),
|
|
594
586
|
*,
|
|
595
587
|
_logical_method_name: str | None = None,
|
|
596
588
|
) -> object:
|
|
@@ -601,7 +593,6 @@ class AsyncDriver:
|
|
|
601
593
|
params: Normalized method parameters.
|
|
602
594
|
context: Immutable operation configuration.
|
|
603
595
|
include_auth: Whether to include captured authentication.
|
|
604
|
-
compatibility_warning_codes: Sanitized compatibility notices.
|
|
605
596
|
_logical_method_name: Optional logical operation name when it
|
|
606
597
|
differs from the wire method.
|
|
607
598
|
|
|
@@ -615,10 +606,7 @@ class AsyncDriver:
|
|
|
615
606
|
consumption, or cleanup fails.
|
|
616
607
|
"""
|
|
617
608
|
normalized_params = copy.deepcopy(params)
|
|
618
|
-
options = AsyncExecutionOptions(
|
|
619
|
-
compatibility_warning_codes=compatibility_warning_codes,
|
|
620
|
-
logical_method_name=_logical_method_name,
|
|
621
|
-
)
|
|
609
|
+
options = AsyncExecutionOptions(logical_method_name=_logical_method_name)
|
|
622
610
|
return await self._execute_rpc(
|
|
623
611
|
method_name,
|
|
624
612
|
normalized_params,
|