sg-python-api 0.1.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.
@@ -0,0 +1,3 @@
1
+ """Package version shared by public exports and compatibility metadata."""
2
+
3
+ PACKAGE_VERSION = '0.1.0'
@@ -0,0 +1 @@
1
+ """Public compatibility helpers for `shotgun_api3`."""
@@ -0,0 +1,16 @@
1
+ """Provide in-memory sync and async Shotgun test doubles.
2
+
3
+ Configure the chosen client's `set_schema_paths()` with field-schema and
4
+ entity-schema pickle files before constructing instances. Await
5
+ `AsyncShotgun.set_schema_paths()` and `AsyncShotgun.get_schema_paths()`.
6
+ `generate_schema()` can create the files from an existing client.
7
+
8
+ Both clients operate without network connections. `AsyncShotgun` exposes
9
+ awaitable methods over a synchronous in-memory delegate and does not require
10
+ the real client's optional async transport.
11
+ """
12
+
13
+ from ._async import AsyncShotgun
14
+ from ._mockgun import MockgunError, Shotgun, generate_schema
15
+
16
+ __all__ = ['AsyncShotgun', 'MockgunError', 'Shotgun', 'generate_schema']
@@ -0,0 +1,315 @@
1
+ """Awaitable delegation twin of the in-memory mockgun client."""
2
+
3
+ from typing import Any, ClassVar
4
+
5
+ from ._mockgun import Shotgun, expose_find_documentation, expose_find_one_documentation
6
+
7
+
8
+ class AsyncShotgun:
9
+ """Provide the mockgun surface through awaitable methods.
10
+
11
+ Each instance owns a synchronous in-memory delegate; awaitable operations
12
+ execute against that delegate without network I/O. Each subclass receives
13
+ its own delegate class, so changing its schema paths does not change those
14
+ of sibling subclasses.
15
+
16
+ Attributes:
17
+ base_url: Constructor-supplied site URL, preserved unchanged.
18
+ config: Mutable mock configuration.
19
+ finds: Number of find operations performed.
20
+ """
21
+
22
+ _sync_type: ClassVar[type[Shotgun]] = Shotgun
23
+ finds: int
24
+
25
+ def __init__( # noqa: PLR0913, PLR0917 - compatibility requires the exact sync signature.
26
+ self,
27
+ base_url: str,
28
+ script_name: str | None = None,
29
+ api_key: str | None = None,
30
+ convert_datetimes_to_utc: bool = True,
31
+ http_proxy: str | None = None,
32
+ connect: bool = True,
33
+ ca_certs: str | None = None,
34
+ login: str | None = None,
35
+ password: str | None = None,
36
+ sudo_as_login: str | None = None,
37
+ session_token: str | None = None,
38
+ auth_token: str | None = None,
39
+ ) -> None:
40
+ """Initialize an asynchronous wrapper around one mock client.
41
+
42
+ Args:
43
+ base_url: Site URL used to initialize mock configuration.
44
+ script_name: Accepted compatibility script name.
45
+ api_key: Accepted compatibility API key.
46
+ convert_datetimes_to_utc: Accepted datetime-conversion setting.
47
+ http_proxy: Accepted compatibility proxy setting.
48
+ connect: Accepted compatibility connection setting.
49
+ ca_certs: Accepted compatibility certificate path.
50
+ login: Accepted compatibility user login.
51
+ password: Accepted compatibility user password.
52
+ sudo_as_login: Accepted compatibility sudo login.
53
+ session_token: Accepted compatibility session token.
54
+ auth_token: Accepted compatibility two-factor token.
55
+
56
+ Raises:
57
+ MockgunError: If schema paths are unset or files are missing.
58
+ TypeError: If arguments do not match the compatibility signature.
59
+ ValueError: If `base_url` has an unsupported or invalid origin.
60
+ """
61
+ self._sync = self._sync_type(
62
+ base_url,
63
+ script_name,
64
+ api_key,
65
+ convert_datetimes_to_utc,
66
+ http_proxy,
67
+ connect,
68
+ ca_certs,
69
+ login,
70
+ password,
71
+ sudo_as_login,
72
+ session_token,
73
+ auth_token,
74
+ )
75
+ self.config = self._sync.config
76
+ self.base_url = self._sync.base_url
77
+
78
+ def __getattr__(self, name: str) -> object:
79
+ """Return the sync twin's live find counter."""
80
+ if name == 'finds':
81
+ return self._sync.finds
82
+ raise AttributeError(f'{type(self).__name__!s} has no attribute {name!r}')
83
+
84
+ def __init_subclass__(cls) -> None:
85
+ """Give each async mock subclass its own synchronous delegate class."""
86
+ super().__init_subclass__()
87
+ cls._sync_type = type(
88
+ f'_{cls.__name__}SyncDelegate',
89
+ (cls._sync_type,),
90
+ {'__module__': __name__},
91
+ )
92
+
93
+ async def batch(self, requests: list[dict[str, Any]]) -> list[object]:
94
+ """Execute supported requests in order and return their result values.
95
+
96
+ Requests apply sequentially. If a later request fails, earlier
97
+ mutations remain applied.
98
+
99
+ Args:
100
+ requests: Create, update, and delete request dictionaries.
101
+
102
+ Returns:
103
+ Per-request results in input order.
104
+
105
+ Raises:
106
+ ShotgunError: If a request or delegated operation is invalid.
107
+ """
108
+ return self._sync.batch(requests)
109
+
110
+ async def create(
111
+ self,
112
+ entity_type: str,
113
+ data: dict[str, Any],
114
+ return_fields: list[str] | None = None,
115
+ ) -> dict[str, object]:
116
+ """Create and return an entity in the in-memory database.
117
+
118
+ Args:
119
+ entity_type: Schema entity type to create.
120
+ data: Field values for the new entity.
121
+ return_fields: Fields to return instead of the fields in `data`.
122
+
123
+ Returns:
124
+ Created entity identity and the selected field values.
125
+
126
+ Raises:
127
+ ShotgunError: If the entity, fields, or values are invalid.
128
+ """
129
+ return self._sync.create(entity_type, data, return_fields)
130
+
131
+ async def delete(self, entity_type: str, entity_id: int) -> bool:
132
+ """Retire an active entity.
133
+
134
+ Args:
135
+ entity_type: Schema entity type to retire.
136
+ entity_id: ID of the existing entity.
137
+
138
+ Returns:
139
+ `True` when the entity changed state, otherwise `False`.
140
+
141
+ Raises:
142
+ ShotgunError: If the entity type or ID is unknown.
143
+ """
144
+ return self._sync.delete(entity_type, entity_id)
145
+
146
+ @expose_find_documentation
147
+ async def find( # noqa: PLR0913, PLR0917 - compatibility requires the exact sync signature.
148
+ self,
149
+ entity_type: str,
150
+ filters: list[Any] | tuple[Any, ...] | dict[str, Any],
151
+ fields: list[str] | None = None,
152
+ order: list[dict[str, str]] | None = None,
153
+ filter_operator: str | None = None,
154
+ limit: int = 0,
155
+ retired_only: bool = False,
156
+ page: int = 0,
157
+ include_archived_projects: bool = True,
158
+ additional_filter_presets: object = None,
159
+ ) -> list[dict[str, object]]:
160
+ return self._sync.find(
161
+ entity_type,
162
+ filters,
163
+ fields,
164
+ order,
165
+ filter_operator,
166
+ limit,
167
+ retired_only,
168
+ page,
169
+ include_archived_projects,
170
+ additional_filter_presets,
171
+ )
172
+
173
+ @expose_find_one_documentation
174
+ async def find_one( # noqa: PLR0913, PLR0917 - compatibility requires the exact sync signature.
175
+ self,
176
+ entity_type: str,
177
+ filters: list[Any] | tuple[Any, ...] | dict[str, Any],
178
+ fields: list[str] | None = None,
179
+ order: list[dict[str, str]] | None = None,
180
+ filter_operator: str | None = None,
181
+ retired_only: bool = False,
182
+ include_archived_projects: bool = True,
183
+ additional_filter_presets: object = None,
184
+ ) -> dict[str, object] | None:
185
+ return self._sync.find_one(
186
+ entity_type,
187
+ filters,
188
+ fields,
189
+ order,
190
+ filter_operator,
191
+ retired_only,
192
+ include_archived_projects,
193
+ additional_filter_presets,
194
+ )
195
+
196
+ @classmethod
197
+ async def get_schema_paths(cls) -> tuple[str | None, str | None]:
198
+ """Return the schema paths configured for mockgun clients.
199
+
200
+ Returns:
201
+ Field-schema and entity-schema paths, in that order.
202
+ """
203
+ return cls._sync_type.get_schema_paths()
204
+
205
+ async def revive(self, entity_type: str, entity_id: int) -> bool:
206
+ """Restore a retired entity to active state.
207
+
208
+ Args:
209
+ entity_type: Schema entity type to restore.
210
+ entity_id: ID of the existing entity.
211
+
212
+ Returns:
213
+ `True` when the entity changed state, otherwise `False`.
214
+
215
+ Raises:
216
+ ShotgunError: If the entity type or ID is unknown.
217
+ """
218
+ return self._sync.revive(entity_type, entity_id)
219
+
220
+ async def schema_entity_read(
221
+ self,
222
+ project_entity: dict[str, Any] | None = None,
223
+ ) -> dict[str, object]:
224
+ """Return the loaded entity schema.
225
+
226
+ Args:
227
+ project_entity: Accepted for public-client compatibility and
228
+ ignored.
229
+
230
+ Returns:
231
+ The live entity-schema dictionary. Mutations affect this client.
232
+ """
233
+ return self._sync.schema_entity_read(project_entity)
234
+
235
+ async def schema_field_read(
236
+ self,
237
+ entity_type: str,
238
+ field_name: str | None = None,
239
+ project_entity: dict[str, Any] | None = None,
240
+ ) -> dict[str, object]:
241
+ """Return the loaded field schema for an entity or one field.
242
+
243
+ Args:
244
+ entity_type: Entity type whose fields to return.
245
+ field_name: Optional field name to select.
246
+ project_entity: Accepted for public-client compatibility and
247
+ ignored.
248
+
249
+ Returns:
250
+ The live entity field-schema dictionary when no field is selected.
251
+ Otherwise, a new dictionary containing the selected field and its
252
+ shared schema value, or an empty dictionary for an unknown field.
253
+ Mutating shared schema values affects this client.
254
+
255
+ Raises:
256
+ KeyError: If `entity_type` is absent from the loaded schema.
257
+ """
258
+ return self._sync.schema_field_read(entity_type, field_name, project_entity)
259
+
260
+ async def schema_read(
261
+ self,
262
+ project_entity: dict[str, Any] | None = None,
263
+ ) -> dict[str, object]:
264
+ """Return the loaded field schema.
265
+
266
+ Args:
267
+ project_entity: Accepted for public-client compatibility and
268
+ ignored.
269
+
270
+ Returns:
271
+ The live field-schema dictionary. Mutations affect this client.
272
+ """
273
+ return self._sync.schema_read(project_entity)
274
+
275
+ @classmethod
276
+ async def set_schema_paths(
277
+ cls,
278
+ schema_path: str,
279
+ schema_entity_path: str,
280
+ ) -> None:
281
+ """Configure the schema files loaded by future mockgun clients.
282
+
283
+ Args:
284
+ schema_path: Path to the field-schema pickle.
285
+ schema_entity_path: Path to the entity-schema pickle.
286
+ """
287
+ cls._sync_type.set_schema_paths(schema_path, schema_entity_path)
288
+
289
+ async def update(
290
+ self,
291
+ entity_type: str,
292
+ entity_id: int,
293
+ data: dict[str, Any],
294
+ multi_entity_update_modes: dict[str, str] | None = None,
295
+ ) -> list[dict[str, object]]:
296
+ """Update an entity and return the official one-item result list.
297
+
298
+ Args:
299
+ entity_type: Schema entity type to update.
300
+ entity_id: ID of the existing entity.
301
+ data: Replacement field values.
302
+ multi_entity_update_modes: Per-field replacement modes.
303
+
304
+ Returns:
305
+ One updated entity containing identity and submitted fields.
306
+
307
+ Raises:
308
+ ShotgunError: If the entity, fields, or values are invalid.
309
+ """
310
+ return self._sync.update(
311
+ entity_type,
312
+ entity_id,
313
+ data,
314
+ multi_entity_update_modes,
315
+ )