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
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""Build and apply TCP keepalive socket options."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import socket
|
|
6
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
7
|
+
|
|
8
|
+
import urllib3
|
|
9
|
+
from urllib3.connection import HTTPConnection, HTTPSConnection
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from collections.abc import Callable, Iterable
|
|
13
|
+
|
|
14
|
+
from urllib3.response import HTTPResponse
|
|
15
|
+
|
|
16
|
+
SocketOption = tuple[int, int, int]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _keepalive_timings(target: int) -> tuple[int, int, int]:
|
|
20
|
+
"""Map a nominal target to whole-second probe timings."""
|
|
21
|
+
idle = target // 2
|
|
22
|
+
interval = -(-(target - idle) // 3)
|
|
23
|
+
return idle, interval, 3
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def keepalive_socket_options(target: int | None) -> tuple[SocketOption, ...]:
|
|
27
|
+
"""Return the available options for a nominal keepalive target.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
target: Validated target in seconds, or `None` to disable keepalive.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Enablement first, followed by available platform timing options.
|
|
34
|
+
"""
|
|
35
|
+
if target is None:
|
|
36
|
+
return ()
|
|
37
|
+
|
|
38
|
+
idle, interval, count = _keepalive_timings(target)
|
|
39
|
+
options: list[SocketOption] = [(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)]
|
|
40
|
+
idle_option = getattr(socket, 'TCP_KEEPIDLE', None)
|
|
41
|
+
if idle_option is None:
|
|
42
|
+
idle_option = getattr(socket, 'TCP_KEEPALIVE', None)
|
|
43
|
+
if idle_option is not None:
|
|
44
|
+
options.append((socket.IPPROTO_TCP, idle_option, idle))
|
|
45
|
+
if hasattr(socket, 'TCP_KEEPINTVL'):
|
|
46
|
+
options.append((socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, interval))
|
|
47
|
+
if hasattr(socket, 'TCP_KEEPCNT'):
|
|
48
|
+
options.append((socket.IPPROTO_TCP, socket.TCP_KEEPCNT, count))
|
|
49
|
+
return tuple(options)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def tune_socket(sock: object, options: Iterable[SocketOption]) -> None:
|
|
53
|
+
"""Apply each supported socket option without failing on OS refusals.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
sock: Socket-like object, which may lack `setsockopt`.
|
|
57
|
+
options: Options to apply in order.
|
|
58
|
+
"""
|
|
59
|
+
setsockopt = getattr(sock, 'setsockopt', None)
|
|
60
|
+
if setsockopt is None:
|
|
61
|
+
return
|
|
62
|
+
for level, option, value in options:
|
|
63
|
+
try:
|
|
64
|
+
setsockopt(level, option, value)
|
|
65
|
+
except OSError:
|
|
66
|
+
continue
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def connection_pool_classes(
|
|
70
|
+
idle_limit: float | None,
|
|
71
|
+
keepalive: tuple[SocketOption, ...],
|
|
72
|
+
clock: Callable[[], float],
|
|
73
|
+
) -> dict[str, type[urllib3.HTTPConnectionPool]]:
|
|
74
|
+
"""Create isolated HTTP and HTTPS pool classes with one connection policy.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
idle_limit: Validated idle limit in seconds, or `None` to disable
|
|
78
|
+
expiry.
|
|
79
|
+
keepalive: Socket options to apply after connection setup.
|
|
80
|
+
clock: Monotonic clock returning seconds.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
New pool classes indexed by scheme, with policy-specific connection
|
|
84
|
+
classes.
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
class _HTTPConnection(HTTPConnection):
|
|
88
|
+
"""Track response arrival and tune each socket after connection setup."""
|
|
89
|
+
|
|
90
|
+
_clock = staticmethod(clock)
|
|
91
|
+
_idle_limit = idle_limit
|
|
92
|
+
_keepalive = keepalive
|
|
93
|
+
_response_at: float | None = None
|
|
94
|
+
|
|
95
|
+
def connect(self) -> None:
|
|
96
|
+
"""Open the connection and apply best-effort keepalive tuning.
|
|
97
|
+
|
|
98
|
+
Raises:
|
|
99
|
+
OSError: If connection setup fails.
|
|
100
|
+
urllib3.exceptions.HTTPError: If connection or proxy setup
|
|
101
|
+
fails.
|
|
102
|
+
"""
|
|
103
|
+
self._response_at = None
|
|
104
|
+
super().connect()
|
|
105
|
+
tune_socket(self.sock, self._keepalive)
|
|
106
|
+
|
|
107
|
+
def getresponse(self) -> HTTPResponse:
|
|
108
|
+
"""Record time after headers and any preloaded body are received.
|
|
109
|
+
|
|
110
|
+
Raises:
|
|
111
|
+
OSError: If receiving the response fails.
|
|
112
|
+
urllib3.exceptions.HTTPError: If the response cannot be
|
|
113
|
+
received.
|
|
114
|
+
"""
|
|
115
|
+
response = super().getresponse()
|
|
116
|
+
self._response_at = self._clock()
|
|
117
|
+
return response
|
|
118
|
+
|
|
119
|
+
@property
|
|
120
|
+
def is_connected(self) -> bool:
|
|
121
|
+
"""Return whether the connection is unexpired and still connected."""
|
|
122
|
+
if (
|
|
123
|
+
self._idle_limit is not None
|
|
124
|
+
and self._response_at is not None
|
|
125
|
+
and self._clock() - self._response_at > self._idle_limit
|
|
126
|
+
):
|
|
127
|
+
return False
|
|
128
|
+
return super().is_connected
|
|
129
|
+
|
|
130
|
+
class _HTTPSConnection(_HTTPConnection, HTTPSConnection):
|
|
131
|
+
"""Apply the connection policy around HTTPS setup, including proxy tunnels."""
|
|
132
|
+
|
|
133
|
+
class _HTTPConnectionPool(urllib3.HTTPConnectionPool):
|
|
134
|
+
"""Pool HTTP connections under this policy."""
|
|
135
|
+
|
|
136
|
+
# urllib3's connection protocols reject its concrete classes under strict typing.
|
|
137
|
+
ConnectionCls = cast('Any', _HTTPConnection)
|
|
138
|
+
|
|
139
|
+
class _HTTPSConnectionPool(urllib3.HTTPSConnectionPool):
|
|
140
|
+
"""Pool HTTPS connections under this policy."""
|
|
141
|
+
|
|
142
|
+
ConnectionCls = cast('Any', _HTTPSConnection)
|
|
143
|
+
|
|
144
|
+
return {'http': _HTTPConnectionPool, 'https': _HTTPSConnectionPool}
|
shotgun_api3/_crud.py
CHANGED
|
@@ -2,187 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
import copy
|
|
4
4
|
import dataclasses
|
|
5
|
-
import inspect
|
|
6
|
-
from collections.abc import Callable
|
|
7
5
|
from typing import Any, Literal, cast
|
|
8
6
|
|
|
9
7
|
from . import _protocol
|
|
10
8
|
from ._errors import ShotgunError
|
|
11
|
-
from ._signatures import bind_arguments, expose_signature
|
|
12
|
-
|
|
13
|
-
_FIND_DOCSTRING = """Find entities matching the supplied filters.
|
|
14
|
-
|
|
15
|
-
Args:
|
|
16
|
-
entity_type: Entity type to find.
|
|
17
|
-
filters: Filters in list or dict syntax.
|
|
18
|
-
fields: Optional fields to return; defaults to `id`.
|
|
19
|
-
order: Optional field and direction sort specifications.
|
|
20
|
-
filter_operator: `'all'` or `'any'` for list-syntax filters.
|
|
21
|
-
limit: Maximum entities to return, or `0` for no limit.
|
|
22
|
-
retired_only: Return retired entities instead of active entities.
|
|
23
|
-
page: Specific page to return, or `0` to read all pages.
|
|
24
|
-
include_archived_projects: Include entities from archived projects.
|
|
25
|
-
additional_filter_presets: Optional server-side filter presets.
|
|
26
|
-
|
|
27
|
-
Returns:
|
|
28
|
-
Matching entities in server order.
|
|
29
|
-
|
|
30
|
-
Raises:
|
|
31
|
-
TypeError: If arguments do not match the documented signature.
|
|
32
|
-
ShotgunError: If an RPC fault or terminal transport failure
|
|
33
|
-
occurs, or if filters, paging, ordering, or a server result is invalid.
|
|
34
|
-
ProtocolError: If a server request returns an HTTP error.
|
|
35
|
-
ValueError: If authenticated HTTP violates the configured origin policy.
|
|
36
|
-
"""
|
|
37
|
-
_FIND_ONE_DOCSTRING = """Return the first entity matching the supplied filters.
|
|
38
|
-
|
|
39
|
-
Args:
|
|
40
|
-
entity_type: Entity type to find.
|
|
41
|
-
filters: Filters in list or dict syntax.
|
|
42
|
-
fields: Optional fields to return; defaults to `id`.
|
|
43
|
-
order: Optional field and direction sort specifications.
|
|
44
|
-
filter_operator: `'all'` or `'any'` for list-syntax filters.
|
|
45
|
-
retired_only: Return a retired entity instead of an active entity.
|
|
46
|
-
include_archived_projects: Include entities from archived projects.
|
|
47
|
-
additional_filter_presets: Optional server-side filter presets.
|
|
48
|
-
|
|
49
|
-
Returns:
|
|
50
|
-
The first matching entity, or `None` when no entity matches.
|
|
51
|
-
|
|
52
|
-
Raises:
|
|
53
|
-
TypeError: If arguments do not match the documented signature.
|
|
54
|
-
ShotgunError: If an RPC fault or terminal transport failure
|
|
55
|
-
occurs, or if filters, paging, ordering, or a server result is invalid.
|
|
56
|
-
ProtocolError: If a server request returns an HTTP error.
|
|
57
|
-
ValueError: If authenticated HTTP violates the configured origin policy.
|
|
58
|
-
"""
|
|
59
|
-
_FIND_ONE_PARAMETERS = (
|
|
60
|
-
inspect.Parameter('entity_type', inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=str),
|
|
61
|
-
inspect.Parameter(
|
|
62
|
-
'filters',
|
|
63
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
64
|
-
annotation=list[Any] | tuple[Any, ...] | dict[str, Any],
|
|
65
|
-
),
|
|
66
|
-
inspect.Parameter(
|
|
67
|
-
'fields',
|
|
68
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
69
|
-
default=None,
|
|
70
|
-
annotation=list[str] | None,
|
|
71
|
-
),
|
|
72
|
-
inspect.Parameter(
|
|
73
|
-
'order',
|
|
74
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
75
|
-
default=None,
|
|
76
|
-
annotation=list[dict[str, str]] | None,
|
|
77
|
-
),
|
|
78
|
-
inspect.Parameter(
|
|
79
|
-
'filter_operator',
|
|
80
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
81
|
-
default=None,
|
|
82
|
-
annotation=str | None,
|
|
83
|
-
),
|
|
84
|
-
inspect.Parameter(
|
|
85
|
-
'retired_only',
|
|
86
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
87
|
-
default=False,
|
|
88
|
-
annotation=bool,
|
|
89
|
-
),
|
|
90
|
-
inspect.Parameter(
|
|
91
|
-
'include_archived_projects',
|
|
92
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
93
|
-
default=True,
|
|
94
|
-
annotation=bool,
|
|
95
|
-
),
|
|
96
|
-
inspect.Parameter(
|
|
97
|
-
'additional_filter_presets',
|
|
98
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
99
|
-
default=None,
|
|
100
|
-
annotation=object,
|
|
101
|
-
),
|
|
102
|
-
)
|
|
103
|
-
_FIND_ONE_SIGNATURE = inspect.Signature(
|
|
104
|
-
_FIND_ONE_PARAMETERS,
|
|
105
|
-
return_annotation=dict[str, object] | None,
|
|
106
|
-
)
|
|
107
|
-
_FIND_PARAMETERS = (
|
|
108
|
-
inspect.Parameter('entity_type', inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=str),
|
|
109
|
-
inspect.Parameter(
|
|
110
|
-
'filters',
|
|
111
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
112
|
-
annotation=list[Any] | tuple[Any, ...] | dict[str, Any],
|
|
113
|
-
),
|
|
114
|
-
inspect.Parameter(
|
|
115
|
-
'fields',
|
|
116
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
117
|
-
default=None,
|
|
118
|
-
annotation=list[str] | None,
|
|
119
|
-
),
|
|
120
|
-
inspect.Parameter(
|
|
121
|
-
'order',
|
|
122
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
123
|
-
default=None,
|
|
124
|
-
annotation=list[dict[str, str]] | None,
|
|
125
|
-
),
|
|
126
|
-
inspect.Parameter(
|
|
127
|
-
'filter_operator',
|
|
128
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
129
|
-
default=None,
|
|
130
|
-
annotation=str | None,
|
|
131
|
-
),
|
|
132
|
-
inspect.Parameter(
|
|
133
|
-
'limit',
|
|
134
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
135
|
-
default=0,
|
|
136
|
-
annotation=int,
|
|
137
|
-
),
|
|
138
|
-
inspect.Parameter(
|
|
139
|
-
'retired_only',
|
|
140
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
141
|
-
default=False,
|
|
142
|
-
annotation=bool,
|
|
143
|
-
),
|
|
144
|
-
inspect.Parameter(
|
|
145
|
-
'page',
|
|
146
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
147
|
-
default=0,
|
|
148
|
-
annotation=int,
|
|
149
|
-
),
|
|
150
|
-
inspect.Parameter(
|
|
151
|
-
'include_archived_projects',
|
|
152
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
153
|
-
default=True,
|
|
154
|
-
annotation=bool,
|
|
155
|
-
),
|
|
156
|
-
inspect.Parameter(
|
|
157
|
-
'additional_filter_presets',
|
|
158
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
159
|
-
default=None,
|
|
160
|
-
annotation=object,
|
|
161
|
-
),
|
|
162
|
-
)
|
|
163
|
-
_FIND_SIGNATURE = inspect.Signature(
|
|
164
|
-
_FIND_PARAMETERS,
|
|
165
|
-
return_annotation=list[dict[str, object]],
|
|
166
|
-
)
|
|
167
|
-
_METHOD_FIND_ONE_SIGNATURE = inspect.Signature(
|
|
168
|
-
(
|
|
169
|
-
inspect.Parameter('self', inspect.Parameter.POSITIONAL_OR_KEYWORD),
|
|
170
|
-
*_FIND_ONE_PARAMETERS,
|
|
171
|
-
),
|
|
172
|
-
return_annotation=dict[str, object] | None,
|
|
173
|
-
)
|
|
174
|
-
_METHOD_FIND_SIGNATURE = inspect.Signature(
|
|
175
|
-
(
|
|
176
|
-
inspect.Parameter('self', inspect.Parameter.POSITIONAL_OR_KEYWORD),
|
|
177
|
-
*_FIND_PARAMETERS,
|
|
178
|
-
),
|
|
179
|
-
return_annotation=list[dict[str, object]],
|
|
180
|
-
)
|
|
181
9
|
|
|
182
10
|
|
|
183
11
|
@dataclasses.dataclass(frozen=True)
|
|
184
|
-
class
|
|
185
|
-
"""Collect exact public `find_one` arguments for validation.
|
|
12
|
+
class FindOneOptions:
|
|
13
|
+
"""Collect exact public `find_one` arguments for validation.
|
|
14
|
+
|
|
15
|
+
Attributes:
|
|
16
|
+
entity_type: Entity type to find.
|
|
17
|
+
filters: Filters in list or dict syntax.
|
|
18
|
+
fields: Optional fields to return; defaults to `id`.
|
|
19
|
+
order: Optional field and direction sort specifications.
|
|
20
|
+
filter_operator: `'all'` or `'any'` for list-syntax filters.
|
|
21
|
+
retired_only: Return a retired entity instead of an active entity.
|
|
22
|
+
include_archived_projects: Include entities from archived projects.
|
|
23
|
+
additional_filter_presets: Optional server-side filter presets.
|
|
24
|
+
"""
|
|
186
25
|
|
|
187
26
|
entity_type: str
|
|
188
27
|
filters: list[Any] | tuple[Any, ...] | dict[str, Any]
|
|
@@ -196,11 +35,11 @@ class _FindOneOptions:
|
|
|
196
35
|
|
|
197
36
|
@dataclasses.dataclass(frozen=True)
|
|
198
37
|
class FindOptions:
|
|
199
|
-
"""
|
|
38
|
+
"""Hold the public `find` arguments in a frozen configuration record.
|
|
200
39
|
|
|
201
40
|
Attributes:
|
|
202
41
|
entity_type: Type of entity to query.
|
|
203
|
-
filters: Query filters or
|
|
42
|
+
filters: Query filters in list, tuple, or dict syntax.
|
|
204
43
|
fields: Optional fields to return.
|
|
205
44
|
order: Optional field ordering directives.
|
|
206
45
|
filter_operator: Optional logical operator joining filters.
|
|
@@ -346,54 +185,6 @@ def _validate_nonnegative_integer(value: object, name: str) -> None:
|
|
|
346
185
|
raise ShotgunError(f'{name} must be a nonnegative integer')
|
|
347
186
|
|
|
348
187
|
|
|
349
|
-
def bind_find(
|
|
350
|
-
args: tuple[object, ...],
|
|
351
|
-
kwargs: dict[str, object],
|
|
352
|
-
client_name: str,
|
|
353
|
-
) -> FindOptions:
|
|
354
|
-
"""Bind runtime arguments with client-specific `find` errors.
|
|
355
|
-
|
|
356
|
-
Args:
|
|
357
|
-
args: Positional public arguments.
|
|
358
|
-
kwargs: Keyword public arguments.
|
|
359
|
-
client_name: Public client class name for error attribution.
|
|
360
|
-
|
|
361
|
-
Returns:
|
|
362
|
-
Bound find options retaining the supplied argument values without
|
|
363
|
-
copying mutable containers.
|
|
364
|
-
|
|
365
|
-
Raises:
|
|
366
|
-
TypeError: If the arguments do not match the public signature.
|
|
367
|
-
"""
|
|
368
|
-
bound = bind_arguments(_FIND_SIGNATURE, args, kwargs, f'{client_name}.find()')
|
|
369
|
-
options = cast('Callable[..., FindOptions]', FindOptions)
|
|
370
|
-
return options(**bound.arguments)
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
def bind_find_one(
|
|
374
|
-
args: tuple[object, ...],
|
|
375
|
-
kwargs: dict[str, object],
|
|
376
|
-
client_name: str,
|
|
377
|
-
) -> _FindOneOptions:
|
|
378
|
-
"""Bind runtime arguments with client-specific `find_one` errors.
|
|
379
|
-
|
|
380
|
-
Args:
|
|
381
|
-
args: Positional public arguments.
|
|
382
|
-
kwargs: Keyword public arguments.
|
|
383
|
-
client_name: Public client class name for error attribution.
|
|
384
|
-
|
|
385
|
-
Returns:
|
|
386
|
-
Bound find-one options retaining the supplied argument values without
|
|
387
|
-
copying mutable containers.
|
|
388
|
-
|
|
389
|
-
Raises:
|
|
390
|
-
TypeError: If the arguments do not match the public signature.
|
|
391
|
-
"""
|
|
392
|
-
bound = bind_arguments(_FIND_ONE_SIGNATURE, args, kwargs, f'{client_name}.find_one()')
|
|
393
|
-
options = cast('Callable[..., _FindOneOptions]', _FindOneOptions)
|
|
394
|
-
return options(**bound.arguments)
|
|
395
|
-
|
|
396
|
-
|
|
397
188
|
def build_entity_action_params(entity_type: str, entity_id: int) -> dict[str, object]:
|
|
398
189
|
"""Build parameters for delete and revive operations.
|
|
399
190
|
|
|
@@ -447,36 +238,18 @@ def build_page_params(plan: _FindPlan, page_number: int, convert_utc: bool) -> o
|
|
|
447
238
|
|
|
448
239
|
Returns:
|
|
449
240
|
Detached transformed page parameters.
|
|
241
|
+
|
|
242
|
+
Raises:
|
|
243
|
+
ValueError: If a naive datetime cannot be converted to UTC.
|
|
244
|
+
OverflowError: If converting an aware datetime to UTC exceeds the
|
|
245
|
+
supported datetime range.
|
|
246
|
+
OSError: If the platform cannot resolve a local datetime.
|
|
450
247
|
"""
|
|
451
248
|
built = dict(plan.params)
|
|
452
249
|
built['paging'] = {**plan.paging, 'current_page': page_number}
|
|
453
250
|
return _protocol.transform_outbound(built, convert_utc)
|
|
454
251
|
|
|
455
252
|
|
|
456
|
-
def expose_find_one_signature(function: Callable[..., object]) -> Callable[..., object]:
|
|
457
|
-
"""Expose the documented `find_one` signature and documentation.
|
|
458
|
-
|
|
459
|
-
Args:
|
|
460
|
-
function: Variadic method implementation.
|
|
461
|
-
|
|
462
|
-
Returns:
|
|
463
|
-
The same function with its public runtime contract attached.
|
|
464
|
-
"""
|
|
465
|
-
return expose_signature(function, _METHOD_FIND_ONE_SIGNATURE, _FIND_ONE_DOCSTRING)
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
def expose_find_signature(function: Callable[..., object]) -> Callable[..., object]:
|
|
469
|
-
"""Expose the documented `find` signature and documentation.
|
|
470
|
-
|
|
471
|
-
Args:
|
|
472
|
-
function: Variadic method implementation.
|
|
473
|
-
|
|
474
|
-
Returns:
|
|
475
|
-
The same function with its public runtime contract attached.
|
|
476
|
-
"""
|
|
477
|
-
return expose_signature(function, _METHOD_FIND_SIGNATURE, _FIND_DOCSTRING)
|
|
478
|
-
|
|
479
|
-
|
|
480
253
|
def finalize_find(
|
|
481
254
|
records: list[dict[str, object]],
|
|
482
255
|
options: FindOptions,
|
|
@@ -499,7 +272,7 @@ def finalize_find(
|
|
|
499
272
|
return _protocol.inject_local_paths(records, local_path_field)
|
|
500
273
|
|
|
501
274
|
|
|
502
|
-
def find_options_from_one(options:
|
|
275
|
+
def find_options_from_one(options: FindOneOptions) -> FindOptions:
|
|
503
276
|
"""Convert bound find-one arguments into a one-result find plan.
|
|
504
277
|
|
|
505
278
|
Args:
|
|
@@ -544,11 +317,13 @@ def prepare_find(options: FindOptions) -> _PreparedFind:
|
|
|
544
317
|
Detached inputs ready for server-aware paging.
|
|
545
318
|
|
|
546
319
|
Raises:
|
|
547
|
-
ShotgunError: If paging or ordering is invalid.
|
|
320
|
+
ShotgunError: If fields, paging, or ordering is invalid.
|
|
548
321
|
Fault: If filter syntax is invalid.
|
|
549
322
|
"""
|
|
550
323
|
_validate_nonnegative_integer(options.limit, 'limit')
|
|
551
324
|
_validate_nonnegative_integer(options.page, 'page')
|
|
325
|
+
if isinstance(options.fields, (str, bytes)):
|
|
326
|
+
raise ShotgunError('find fields must be an iterable of strings or None')
|
|
552
327
|
translated_filters = copy.deepcopy(
|
|
553
328
|
_protocol.translate_filters(
|
|
554
329
|
_protocol.require_filter_container(options.filters, options.filter_operator),
|