sg-python-api 0.2.0__py3-none-any.whl → 0.2.1__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.2.0.dist-info → sg_python_api-0.2.1.dist-info}/METADATA +14 -14
- {sg_python_api-0.2.0.dist-info → sg_python_api-0.2.1.dist-info}/RECORD +12 -12
- shotgun_api3/lib/mockgun/_events.py +25 -4
- shotgun_api3/lib/mockgun/_handlers.py +1 -6
- shotgun_api3/lib/mockgun/_links.py +256 -98
- shotgun_api3/lib/mockgun/_query.py +79 -37
- shotgun_api3/lib/mockgun/_retirement.py +124 -29
- shotgun_api3/lib/mockgun/_store.py +153 -40
- shotgun_api3/lib/mockgun/_summaries.py +18 -17
- shotgun_api3/lib/mockgun/_threads.py +4 -4
- {sg_python_api-0.2.0.dist-info → sg_python_api-0.2.1.dist-info}/WHEEL +0 -0
- {sg_python_api-0.2.0.dist-info → sg_python_api-0.2.1.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.2.
|
|
3
|
+
Version: 0.2.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.5`. 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.2.
|
|
49
|
-
through the switch, and the [compatibility reference](https://github.com/dactylo/sg-python-api/blob/v0.2.
|
|
48
|
+
site before replacing its production client. The [migration guide](https://github.com/dactylo/sg-python-api/blob/v0.2.1/docs/migration-guide.md) walks
|
|
49
|
+
through the switch, and the [compatibility reference](https://github.com/dactylo/sg-python-api/blob/v0.2.1/COMPATIBILITY.md) lists the differences.
|
|
50
50
|
|
|
51
51
|
## Installation
|
|
52
52
|
|
|
@@ -55,7 +55,7 @@ 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.2.
|
|
58
|
+
the [migration steps](https://github.com/dactylo/sg-python-api/blob/v0.2.1/docs/migration-guide.md#install-the-replacement) to replace it.
|
|
59
59
|
|
|
60
60
|
From a checkout, install into the Python environment that runs your application:
|
|
61
61
|
|
|
@@ -127,23 +127,23 @@ asyncio.run(main())
|
|
|
127
127
|
|
|
128
128
|
The output matches the synchronous example. The `async with` block closes the client even when an
|
|
129
129
|
operation fails. Share an `AsyncShotgun` only among tasks on one event loop. See the
|
|
130
|
-
[async reference](https://github.com/dactylo/sg-python-api/blob/v0.2.
|
|
130
|
+
[async reference](https://github.com/dactylo/sg-python-api/blob/v0.2.1/COMPATIBILITY.md#async-extension-surfaces) for lifecycle and cancellation
|
|
131
131
|
details.
|
|
132
132
|
|
|
133
133
|
## Documentation
|
|
134
134
|
|
|
135
135
|
| If you want to... | Read |
|
|
136
136
|
| ------------------------------------------------------------------ | ---------------------------------------------------------------------------------- |
|
|
137
|
-
| Replace Autodesk's client in an existing application | [Migration guide](https://github.com/dactylo/sg-python-api/blob/v0.2.
|
|
138
|
-
| Check what behaves differently from Autodesk's client | [Compatibility](https://github.com/dactylo/sg-python-api/blob/v0.2.
|
|
139
|
-
| Tune pooling, TCP keepalive, or page prefetch, or observe requests | [Configuration extensions](https://github.com/dactylo/sg-python-api/blob/v0.2.
|
|
140
|
-
| Confirm which client loads and run a smoke test | [Testing an installation](https://github.com/dactylo/sg-python-api/blob/v0.2.
|
|
141
|
-
| Compare measured latency and transfer memory | [Benchmarks](https://github.com/dactylo/sg-python-api/blob/v0.2.
|
|
142
|
-
| See changes by version | [Changelog](https://github.com/dactylo/sg-python-api/blob/v0.2.
|
|
137
|
+
| Replace Autodesk's client in an existing application | [Migration guide](https://github.com/dactylo/sg-python-api/blob/v0.2.1/docs/migration-guide.md) |
|
|
138
|
+
| Check what behaves differently from Autodesk's client | [Compatibility](https://github.com/dactylo/sg-python-api/blob/v0.2.1/COMPATIBILITY.md) |
|
|
139
|
+
| Tune pooling, TCP keepalive, or page prefetch, or observe requests | [Configuration extensions](https://github.com/dactylo/sg-python-api/blob/v0.2.1/COMPATIBILITY.md#configuration-and-observer-extensions) |
|
|
140
|
+
| Confirm which client loads and run a smoke test | [Testing an installation](https://github.com/dactylo/sg-python-api/blob/v0.2.1/docs/testing.md) |
|
|
141
|
+
| Compare measured latency and transfer memory | [Benchmarks](https://github.com/dactylo/sg-python-api/blob/v0.2.1/docs/benchmarks.md) |
|
|
142
|
+
| See changes by version | [Changelog](https://github.com/dactylo/sg-python-api/blob/v0.2.1/CHANGELOG.md) |
|
|
143
143
|
|
|
144
144
|
## Development
|
|
145
145
|
|
|
146
|
-
See the [development guide](https://github.com/dactylo/sg-python-api/blob/v0.2.
|
|
146
|
+
See the [development guide](https://github.com/dactylo/sg-python-api/blob/v0.2.1/docs/development.md) for the required tools, CI, and dependency locks.
|
|
147
147
|
With those tools installed, run:
|
|
148
148
|
|
|
149
149
|
```sh
|
|
@@ -151,11 +151,11 @@ make setup
|
|
|
151
151
|
make check TEST_FLAGS="-m 'not live'"
|
|
152
152
|
```
|
|
153
153
|
|
|
154
|
-
See [live-site tests](https://github.com/dactylo/sg-python-api/blob/v0.2.
|
|
154
|
+
See [live-site tests](https://github.com/dactylo/sg-python-api/blob/v0.2.1/docs/development.md#live-site-tests) to configure tests that create and
|
|
155
155
|
retire records on a disposable site.
|
|
156
156
|
|
|
157
157
|
## License
|
|
158
158
|
|
|
159
|
-
sg-python-api is available under the [MIT License](https://github.com/dactylo/sg-python-api/blob/v0.2.
|
|
159
|
+
sg-python-api is available under the [MIT License](https://github.com/dactylo/sg-python-api/blob/v0.2.1/LICENSE). It is an independent project and is
|
|
160
160
|
not affiliated with or endorsed by Autodesk. Flow Production Tracking is a product of Autodesk,
|
|
161
161
|
Inc.
|
|
@@ -27,14 +27,14 @@ shotgun_api3/lib/mockgun/_activity.py,sha256=MK09A1FERRN9Tg2sl2tCtu7n7Gebi-qJKAl
|
|
|
27
27
|
shotgun_api3/lib/mockgun/_async_client.py,sha256=UqsoACBDzjkCY191E09grBWAGBm-E8nUhytSJRBATOo,7411
|
|
28
28
|
shotgun_api3/lib/mockgun/_dates.py,sha256=d0lAIM-SaKjj-vtwe7qg5OXHwgGk42N8OQtxYQ8GWnE,6682
|
|
29
29
|
shotgun_api3/lib/mockgun/_errors.py,sha256=LL8WI7Sv-p51pEe92k1UsNGygTHXmVki1N0ntJMVnj0,620
|
|
30
|
-
shotgun_api3/lib/mockgun/_events.py,sha256=
|
|
30
|
+
shotgun_api3/lib/mockgun/_events.py,sha256=qHmUoa4p3dpibPpmsCQef6KECqWQXp3cYQVt_t1J5zY,37812
|
|
31
31
|
shotgun_api3/lib/mockgun/_follows.py,sha256=TeSRhlWWYKukz7ZOFa5KDfwMl7zGdQwqHzR7i24ej2E,8401
|
|
32
|
-
shotgun_api3/lib/mockgun/_handlers.py,sha256=
|
|
33
|
-
shotgun_api3/lib/mockgun/_links.py,sha256=
|
|
32
|
+
shotgun_api3/lib/mockgun/_handlers.py,sha256=YOb7YXZz0SUoNpTMRy-E8yxzzlsS1SULT0K1kElX-Zo,23428
|
|
33
|
+
shotgun_api3/lib/mockgun/_links.py,sha256=TVThdzw0EqPspnUWpHv9iPyMPkvBhbpxASUQH-sSJb4,24305
|
|
34
34
|
shotgun_api3/lib/mockgun/_new_client.py,sha256=M9qzuT910xQDW1GwIxhZ8cCfdeMucT0FpAe4CVPmZ-U,2981
|
|
35
35
|
shotgun_api3/lib/mockgun/_presets.py,sha256=R8CAWg-sPGj6OX2yWfivJ1g5YNKIuU7D9LyAXxR2hFo,20339
|
|
36
|
-
shotgun_api3/lib/mockgun/_query.py,sha256=
|
|
37
|
-
shotgun_api3/lib/mockgun/_retirement.py,sha256=
|
|
36
|
+
shotgun_api3/lib/mockgun/_query.py,sha256=0i1JH4lwpEJogvur1vsPCl7cbN5MiJHaDUvKHo7Irlk,92186
|
|
37
|
+
shotgun_api3/lib/mockgun/_retirement.py,sha256=kTwUWbsUEZp00F8957ByBsEsp6GenSx35vlxv5WqGGg,18051
|
|
38
38
|
shotgun_api3/lib/mockgun/_schema.py,sha256=MJokdscaJP1zVlNtZR679Z3eW3r3PuMvAtYmiLtg9So,7069
|
|
39
39
|
shotgun_api3/lib/mockgun/_schema_writes.py,sha256=lxxrtCDK6FG2_RpikYYerdMlD9YcH16fHGqUcv4CDoo,16781
|
|
40
40
|
shotgun_api3/lib/mockgun/_search.py,sha256=xhTD_5nILWHs7jfXnJKAJZVQS4CQAYN0DwTBf4izoj8,14507
|
|
@@ -43,16 +43,16 @@ shotgun_api3/lib/mockgun/_sessions.py,sha256=3p4PL-5eNypS8WwdhKX5RNLWKM_alhqN2pD
|
|
|
43
43
|
shotgun_api3/lib/mockgun/_site.py,sha256=cj3HeblefYV0jX-4P8ginh5EvVG1thUEaxSV4dN_Q_I,6107
|
|
44
44
|
shotgun_api3/lib/mockgun/_site_data.py,sha256=Dkivld3zuCqcpC-R4QhMAxUrhsT3Sqkm7UP6fP6v4lA,23470
|
|
45
45
|
shotgun_api3/lib/mockgun/_storage.py,sha256=OLE09uaO0GoYj_SsUoVCu2MeTl0qW_cDIwlYMXh7EIk,7780
|
|
46
|
-
shotgun_api3/lib/mockgun/_store.py,sha256=
|
|
47
|
-
shotgun_api3/lib/mockgun/_summaries.py,sha256=
|
|
46
|
+
shotgun_api3/lib/mockgun/_store.py,sha256=ufc79zzoLy8A15fOKqxo_BD9ygxsphB8UP0MI77aBFc,65988
|
|
47
|
+
shotgun_api3/lib/mockgun/_summaries.py,sha256=9GwoGr4gm_UKzTrYGkpbO3mDKglqaNywq0qdoYnGEaY,40497
|
|
48
48
|
shotgun_api3/lib/mockgun/_sync_client.py,sha256=Vo-3rm9dxp4_4ulnFN2tf3xCDUCmw_v1OcE8-8UKtRI,7276
|
|
49
|
-
shotgun_api3/lib/mockgun/_threads.py,sha256=
|
|
49
|
+
shotgun_api3/lib/mockgun/_threads.py,sha256=0g1RHgySKzrYheQzfnG1fFAJ7cUhFWuZYH_OuNdmEU4,9632
|
|
50
50
|
shotgun_api3/lib/mockgun/_thumbnails.py,sha256=VG1d4OJCBowtJIhmps8d-DlOCLFNcEyl6fdEG8ylOEU,6169
|
|
51
51
|
shotgun_api3/lib/mockgun/_transport.py,sha256=o4pOjwek9BVVLZYCVRy0ega1qYOnsFipaxGV7sPwKoM,5174
|
|
52
52
|
shotgun_api3/lib/mockgun/_uploads.py,sha256=aUzptrzj4fiMgVQCu_vaiXAsfsmds_YuVeRSz1-5ZH4,16711
|
|
53
53
|
shotgun_api3/lib/mockgun/_wire.py,sha256=OC2B1AziX1y0ugQuso4fQXiK4sAdy_lAF_E5ktvjxFc,4123
|
|
54
54
|
shotgun_api3/lib/mockgun/mockgun.py,sha256=OQaZbVxuAtYdBkO0ItV_KpJ6XsnbbYWA1Oti8Wm51Io,522
|
|
55
|
-
sg_python_api-0.2.
|
|
56
|
-
sg_python_api-0.2.
|
|
57
|
-
sg_python_api-0.2.
|
|
58
|
-
sg_python_api-0.2.
|
|
55
|
+
sg_python_api-0.2.1.dist-info/METADATA,sha256=7l66bxk1MsZPrlvfGKMDvmsS64-HxwzqEXI2Dt5VlWI,7530
|
|
56
|
+
sg_python_api-0.2.1.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
57
|
+
sg_python_api-0.2.1.dist-info/licenses/LICENSE,sha256=V3moMsQxKDchTd3mtXl5J-ODaNBDvFrapOf1DK7Nx_U,1082
|
|
58
|
+
sg_python_api-0.2.1.dist-info/RECORD,,
|
|
@@ -111,6 +111,9 @@ _LIFECYCLE_TYPES = frozenset(
|
|
|
111
111
|
'Asset',
|
|
112
112
|
'PublishedFile',
|
|
113
113
|
'CutItem',
|
|
114
|
+
# 2026-11-10: a lone Cut or Attachment logs only its own lifecycle rows.
|
|
115
|
+
'Cut',
|
|
116
|
+
'Attachment',
|
|
114
117
|
}
|
|
115
118
|
)
|
|
116
119
|
_LINK_TARGETS = {
|
|
@@ -145,6 +148,10 @@ _LINK_UPDATE_FORMS = {
|
|
|
145
148
|
_SCALAR_ENCODINGS = frozenset(
|
|
146
149
|
{'number', 'duration', 'checkbox', 'text', 'list', 'status_list', 'date', 'date_time', 'float'}
|
|
147
150
|
)
|
|
151
|
+
# 2026-11-10 trial capture: no create logs a default it fills into a field of these data types,
|
|
152
|
+
# across 459 Task, 240 Note, 83 Reply and 36 Playlist creates; status list and list defaults are
|
|
153
|
+
# always logged.
|
|
154
|
+
_UNLOGGED_DEFAULT_TYPES = frozenset({'duration', 'number', 'percent', 'text'})
|
|
148
155
|
_WRITE_TYPES = frozenset(
|
|
149
156
|
{
|
|
150
157
|
'Shot',
|
|
@@ -216,6 +223,10 @@ def _create_fields(store: Store, row: Row, supplied: Sequence[str]) -> list[str]
|
|
|
216
223
|
if field not in _CREATE_IGNORED
|
|
217
224
|
and row.get(field) is not None
|
|
218
225
|
and row.get(field) != []
|
|
226
|
+
and not (
|
|
227
|
+
field not in supplied
|
|
228
|
+
and store.schema.field_type(kind, field) in _UNLOGGED_DEFAULT_TYPES
|
|
229
|
+
)
|
|
219
230
|
and not (
|
|
220
231
|
field not in supplied
|
|
221
232
|
and row.get(field) is False
|
|
@@ -718,7 +729,13 @@ def _observed_create_fields(
|
|
|
718
729
|
populated = {
|
|
719
730
|
field
|
|
720
731
|
for field in store.schema.fields[kind]
|
|
721
|
-
if field not in _CREATE_IGNORED
|
|
732
|
+
if field not in _CREATE_IGNORED
|
|
733
|
+
and row.get(field) is not None
|
|
734
|
+
and row.get(field) != []
|
|
735
|
+
and not (
|
|
736
|
+
field not in supplied
|
|
737
|
+
and store.schema.field_type(kind, field) in _UNLOGGED_DEFAULT_TYPES
|
|
738
|
+
)
|
|
722
739
|
}
|
|
723
740
|
for form in _CREATE_FORMS:
|
|
724
741
|
if (kind, session) != (form.kind, form.session):
|
|
@@ -862,10 +879,14 @@ def record_create(
|
|
|
862
879
|
plans = _plan_create(store, row, supplied, context=context)
|
|
863
880
|
if store.schema.declares('EventLogEntry') and store.events_unknown is None:
|
|
864
881
|
if plans is None:
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
882
|
+
# 2026-11-10: a new Project also logs hundreds of rows for the pages,
|
|
883
|
+
# page settings and field preferences the site copies from a template.
|
|
884
|
+
detail = (
|
|
885
|
+
' for the pages and preferences the site creates with it'
|
|
886
|
+
if row['type'] == 'Project'
|
|
887
|
+
else ''
|
|
868
888
|
)
|
|
889
|
+
_unsettled(store, f'{row["type"]} {row["id"]} create has unsettled event rows{detail}')
|
|
869
890
|
else:
|
|
870
891
|
_write_plans(store, plans, context)
|
|
871
892
|
return plans is not None
|
|
@@ -27,7 +27,6 @@ from ._wire import RpcCall
|
|
|
27
27
|
|
|
28
28
|
if TYPE_CHECKING:
|
|
29
29
|
from ._server import FakeServer
|
|
30
|
-
from ._store import FieldValue
|
|
31
30
|
|
|
32
31
|
_Handler: TypeAlias = Callable[['FakeServer', RpcCall, RequestContext], object]
|
|
33
32
|
HANDLERS: dict[str, _Handler] = {}
|
|
@@ -385,6 +384,7 @@ def _update(server: 'FakeServer', call: RpcCall, context: RequestContext) -> obj
|
|
|
385
384
|
entity_type = cast('str', params['type'])
|
|
386
385
|
entity_id = cast('int', params['id'])
|
|
387
386
|
_check_event_write(server, entity_type)
|
|
387
|
+
server.store.check_link_targets(entity_type, fields, 'update')
|
|
388
388
|
kept = kept_members(server.store, entity_type, entity_id, fields)
|
|
389
389
|
effective = server.store.kept_fields(
|
|
390
390
|
server.store.require(entity_type, entity_id), fields, modes, kept
|
|
@@ -401,11 +401,6 @@ def _update(server: 'FakeServer', call: RpcCall, context: RequestContext) -> obj
|
|
|
401
401
|
row = server.store.update(
|
|
402
402
|
entity_type, entity_id, effective, effective_modes, context=context
|
|
403
403
|
)
|
|
404
|
-
for field in kept:
|
|
405
|
-
if len(cast('list[FieldValue]', row[field])) > 1:
|
|
406
|
-
server.store.mark_unknown(
|
|
407
|
-
row, field, 'retained hidden members have unsettled order', order_only=True
|
|
408
|
-
)
|
|
409
404
|
settled = record_update(
|
|
410
405
|
server.store,
|
|
411
406
|
before,
|