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.
- sg_python_api-0.1.0.dist-info/METADATA +177 -0
- sg_python_api-0.1.0.dist-info/RECORD +31 -0
- sg_python_api-0.1.0.dist-info/WHEEL +4 -0
- sg_python_api-0.1.0.dist-info/licenses/LICENSE +21 -0
- shotgun_api3/__init__.py +68 -0
- shotgun_api3/_async_client.py +2906 -0
- shotgun_api3/_async_driver.py +945 -0
- shotgun_api3/_async_httpx2.py +662 -0
- shotgun_api3/_async_transport.py +162 -0
- shotgun_api3/_capabilities.py +165 -0
- shotgun_api3/_client.py +2682 -0
- shotgun_api3/_config.py +1463 -0
- shotgun_api3/_crud.py +916 -0
- shotgun_api3/_driver.py +879 -0
- shotgun_api3/_errors.py +49 -0
- shotgun_api3/_execution.py +273 -0
- shotgun_api3/_files.py +1094 -0
- shotgun_api3/_methods.py +1205 -0
- shotgun_api3/_protocol.py +1347 -0
- shotgun_api3/_sentinel.py +5 -0
- shotgun_api3/_sg_timezone.py +5 -0
- shotgun_api3/_signatures.py +53 -0
- shotgun_api3/_transport.py +901 -0
- shotgun_api3/_version.py +3 -0
- shotgun_api3/lib/__init__.py +1 -0
- shotgun_api3/lib/mockgun/__init__.py +16 -0
- shotgun_api3/lib/mockgun/_async.py +315 -0
- shotgun_api3/lib/mockgun/_mockgun.py +1666 -0
- shotgun_api3/lib/sgtimezone.py +209 -0
- shotgun_api3/py.typed +0 -0
- shotgun_api3/shotgun.py +58 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"""Timezone helpers at the official `shotgun_api3.lib.sgtimezone` path."""
|
|
2
|
+
|
|
3
|
+
import datetime
|
|
4
|
+
import time
|
|
5
|
+
|
|
6
|
+
_EPOCH = datetime.datetime(1970, 1, 1, tzinfo=datetime.UTC)
|
|
7
|
+
_NAIVE_EPOCH = _EPOCH.replace(tzinfo=None)
|
|
8
|
+
_ZERO = datetime.timedelta(0)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class LocalTimezone(datetime.tzinfo):
|
|
12
|
+
"""The process's dynamic system-local timezone.
|
|
13
|
+
|
|
14
|
+
On platforms without pre-epoch local-time support, pre-1970 values use the
|
|
15
|
+
process's standard offset without historical daylight-saving accuracy.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def _isdst(self, dt: datetime.datetime | None) -> bool:
|
|
19
|
+
"""Return whether a local wall time selects daylight-saving time."""
|
|
20
|
+
if dt is None or not time.daylight:
|
|
21
|
+
return False
|
|
22
|
+
|
|
23
|
+
wall_time = (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second)
|
|
24
|
+
time_tuple = (*wall_time, dt.weekday(), 0)
|
|
25
|
+
candidates: list[tuple[float, bool]] = []
|
|
26
|
+
outcomes: list[tuple[float, bool]] = []
|
|
27
|
+
for is_dst in (0, 1):
|
|
28
|
+
try:
|
|
29
|
+
stamp = time.mktime((*time_tuple, is_dst))
|
|
30
|
+
local = time.localtime(stamp)
|
|
31
|
+
except (OSError, OverflowError, ValueError):
|
|
32
|
+
if _is_pre_epoch(dt):
|
|
33
|
+
return False
|
|
34
|
+
raise
|
|
35
|
+
outcome = (stamp, local.tm_isdst > 0)
|
|
36
|
+
outcomes.append(outcome)
|
|
37
|
+
if local[:6] == wall_time and outcome[1] is bool(is_dst):
|
|
38
|
+
candidates.append(outcome)
|
|
39
|
+
|
|
40
|
+
if len(candidates) > 1 and candidates[0][0] != candidates[1][0]:
|
|
41
|
+
candidates.sort(key=lambda candidate: candidate[0])
|
|
42
|
+
return candidates[dt.fold][1]
|
|
43
|
+
|
|
44
|
+
if not candidates and outcomes[0][0] != outcomes[1][0]:
|
|
45
|
+
outcomes.sort(key=lambda outcome: outcome[0])
|
|
46
|
+
return outcomes[dt.fold][1]
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
inferred_stamp = time.mktime((*time_tuple, -1))
|
|
50
|
+
return time.localtime(inferred_stamp).tm_isdst > 0
|
|
51
|
+
except (OSError, OverflowError, ValueError):
|
|
52
|
+
if _is_pre_epoch(dt):
|
|
53
|
+
return False
|
|
54
|
+
raise
|
|
55
|
+
|
|
56
|
+
@staticmethod
|
|
57
|
+
def _offsets() -> tuple[datetime.timedelta, datetime.timedelta]:
|
|
58
|
+
"""Return the process's current standard and daylight offsets."""
|
|
59
|
+
standard = datetime.timedelta(seconds=-time.timezone)
|
|
60
|
+
daylight = datetime.timedelta(seconds=-time.altzone) if time.daylight else standard
|
|
61
|
+
return standard, daylight
|
|
62
|
+
|
|
63
|
+
def dst(self, dt: datetime.datetime | None) -> datetime.timedelta:
|
|
64
|
+
"""Return the daylight-saving adjustment for a local wall time.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
dt: Local wall time, with `fold` selecting an ambiguous occurrence.
|
|
68
|
+
`None` selects standard time.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
The daylight-saving adjustment, or zero when DST is not active.
|
|
72
|
+
"""
|
|
73
|
+
standard, daylight = self._offsets()
|
|
74
|
+
return daylight - standard if self._isdst(dt) else _ZERO
|
|
75
|
+
|
|
76
|
+
def fromutc(self, dt: datetime.datetime) -> datetime.datetime:
|
|
77
|
+
"""Convert UTC fields to the corresponding local wall time.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
dt: Datetime whose fields express UTC and whose `tzinfo` is this
|
|
81
|
+
instance.
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
The equivalent local datetime, with `fold` marking a repeated wall
|
|
85
|
+
time.
|
|
86
|
+
|
|
87
|
+
Raises:
|
|
88
|
+
ValueError: If `dt.tzinfo` is not this instance.
|
|
89
|
+
"""
|
|
90
|
+
if dt.tzinfo is not self:
|
|
91
|
+
raise ValueError('fromutc() requires dt.tzinfo to be self')
|
|
92
|
+
|
|
93
|
+
stamp = (dt.replace(tzinfo=datetime.UTC) - _EPOCH).total_seconds()
|
|
94
|
+
try:
|
|
95
|
+
local = time.localtime(stamp)
|
|
96
|
+
except (OSError, OverflowError, ValueError):
|
|
97
|
+
if stamp >= 0:
|
|
98
|
+
raise
|
|
99
|
+
standard, _daylight = self._offsets()
|
|
100
|
+
return (dt.replace(tzinfo=None) + standard).replace(tzinfo=self, fold=0)
|
|
101
|
+
|
|
102
|
+
standard, daylight = self._offsets()
|
|
103
|
+
dst_difference = (daylight - standard).total_seconds()
|
|
104
|
+
try:
|
|
105
|
+
previous = time.localtime(stamp - dst_difference)
|
|
106
|
+
except (OSError, OverflowError, ValueError):
|
|
107
|
+
if stamp >= 0:
|
|
108
|
+
raise
|
|
109
|
+
standard, _daylight = self._offsets()
|
|
110
|
+
return (dt.replace(tzinfo=None) + standard).replace(tzinfo=self, fold=0)
|
|
111
|
+
fold = bool(dst_difference) and local[:6] == previous[:6]
|
|
112
|
+
return datetime.datetime(
|
|
113
|
+
local.tm_year,
|
|
114
|
+
local.tm_mon,
|
|
115
|
+
local.tm_mday,
|
|
116
|
+
local.tm_hour,
|
|
117
|
+
local.tm_min,
|
|
118
|
+
local.tm_sec,
|
|
119
|
+
microsecond=dt.microsecond,
|
|
120
|
+
tzinfo=self,
|
|
121
|
+
fold=int(fold),
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
def tzname(self, dt: datetime.datetime | None) -> str:
|
|
125
|
+
"""Return the current local timezone name for a wall time.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
dt: Local wall time, with `fold` selecting an ambiguous occurrence.
|
|
129
|
+
`None` selects standard time.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
The platform's standard or daylight timezone name.
|
|
133
|
+
"""
|
|
134
|
+
return time.tzname[int(self._isdst(dt))]
|
|
135
|
+
|
|
136
|
+
def utcoffset(self, dt: datetime.datetime | None) -> datetime.timedelta:
|
|
137
|
+
"""Return the current local offset from UTC for a wall time.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
dt: Local wall time, with `fold` selecting an ambiguous occurrence.
|
|
141
|
+
`None` selects standard time.
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
The current standard or daylight offset from UTC.
|
|
145
|
+
"""
|
|
146
|
+
standard, daylight = self._offsets()
|
|
147
|
+
return daylight if self._isdst(dt) else standard
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class UTC(datetime.tzinfo):
|
|
151
|
+
"""UTC with a constant zero offset."""
|
|
152
|
+
|
|
153
|
+
def dst(self, dt: datetime.datetime | None) -> datetime.timedelta:
|
|
154
|
+
"""Return the zero daylight-saving adjustment.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
dt: Ignored because UTC does not observe daylight-saving time.
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
A zero-length timedelta.
|
|
161
|
+
"""
|
|
162
|
+
del dt
|
|
163
|
+
return _ZERO
|
|
164
|
+
|
|
165
|
+
def tzname(self, dt: datetime.datetime | None) -> str:
|
|
166
|
+
"""Return the UTC timezone name.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
dt: Ignored because the UTC name is constant.
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
The string `UTC`.
|
|
173
|
+
"""
|
|
174
|
+
del dt
|
|
175
|
+
return 'UTC'
|
|
176
|
+
|
|
177
|
+
def utcoffset(self, dt: datetime.datetime | None) -> datetime.timedelta:
|
|
178
|
+
"""Return UTC's zero offset.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
dt: Ignored because the UTC offset is constant.
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
A zero-length timedelta.
|
|
185
|
+
"""
|
|
186
|
+
del dt
|
|
187
|
+
return _ZERO
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
class SgTimezone:
|
|
191
|
+
"""Container exposing UTC and system-local timezone instances.
|
|
192
|
+
|
|
193
|
+
Attributes:
|
|
194
|
+
utc: UTC timezone instance.
|
|
195
|
+
local: System-local timezone instance.
|
|
196
|
+
"""
|
|
197
|
+
|
|
198
|
+
LocalTimezone = LocalTimezone
|
|
199
|
+
UTC = UTC
|
|
200
|
+
|
|
201
|
+
def __init__(self) -> None:
|
|
202
|
+
"""Initialize UTC and local timezone instances."""
|
|
203
|
+
self.utc = UTC()
|
|
204
|
+
self.local = LocalTimezone()
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def _is_pre_epoch(value: datetime.datetime) -> bool:
|
|
208
|
+
"""Return whether a datetime precedes the Unix epoch."""
|
|
209
|
+
return value.replace(tzinfo=None) < _NAIVE_EPOCH
|
shotgun_api3/py.typed
ADDED
|
File without changes
|
shotgun_api3/shotgun.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Expose the synchronous `shotgun_api3.shotgun` compatibility surface.
|
|
2
|
+
|
|
3
|
+
Import this module for the synchronous client and public compatibility names.
|
|
4
|
+
Import initializes the `shotgun_api3` logger and reads
|
|
5
|
+
`SHOTGUN_API_DISABLE_ENTITY_OPTIMIZATION`; the environment value `1` disables
|
|
6
|
+
entity-link optimization.
|
|
7
|
+
|
|
8
|
+
Assigning the module's `SHOTGUN_API_DISABLE_ENTITY_OPTIMIZATION` flag later
|
|
9
|
+
changes the setting used by subsequent request construction.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import logging
|
|
13
|
+
import os
|
|
14
|
+
|
|
15
|
+
from ._capabilities import ClientCapabilities, ServerCapabilities
|
|
16
|
+
from ._client import Shotgun, __version__
|
|
17
|
+
from ._errors import (
|
|
18
|
+
AuthenticationFault,
|
|
19
|
+
Error,
|
|
20
|
+
Fault,
|
|
21
|
+
MissingTwoFactorAuthenticationFault,
|
|
22
|
+
ProtocolError,
|
|
23
|
+
ResponseError,
|
|
24
|
+
ShotgunError,
|
|
25
|
+
ShotgunFileDownloadError,
|
|
26
|
+
ShotgunThumbnailNotReady,
|
|
27
|
+
UserCredentialsNotAllowedForOxygenAuthenticationFault,
|
|
28
|
+
UserCredentialsNotAllowedForSSOAuthenticationFault,
|
|
29
|
+
)
|
|
30
|
+
from ._sg_timezone import SG_TIMEZONE
|
|
31
|
+
from .lib.sgtimezone import SgTimezone
|
|
32
|
+
|
|
33
|
+
LOG = logging.getLogger('shotgun_api3')
|
|
34
|
+
SHOTGUN_API_DISABLE_ENTITY_OPTIMIZATION = (
|
|
35
|
+
os.environ.get('SHOTGUN_API_DISABLE_ENTITY_OPTIMIZATION', '0') == '1'
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
__all__ = [
|
|
39
|
+
'LOG',
|
|
40
|
+
'SG_TIMEZONE',
|
|
41
|
+
'SHOTGUN_API_DISABLE_ENTITY_OPTIMIZATION',
|
|
42
|
+
'AuthenticationFault',
|
|
43
|
+
'ClientCapabilities',
|
|
44
|
+
'Error',
|
|
45
|
+
'Fault',
|
|
46
|
+
'MissingTwoFactorAuthenticationFault',
|
|
47
|
+
'ProtocolError',
|
|
48
|
+
'ResponseError',
|
|
49
|
+
'ServerCapabilities',
|
|
50
|
+
'SgTimezone',
|
|
51
|
+
'Shotgun',
|
|
52
|
+
'ShotgunError',
|
|
53
|
+
'ShotgunFileDownloadError',
|
|
54
|
+
'ShotgunThumbnailNotReady',
|
|
55
|
+
'UserCredentialsNotAllowedForOxygenAuthenticationFault',
|
|
56
|
+
'UserCredentialsNotAllowedForSSOAuthenticationFault',
|
|
57
|
+
'__version__',
|
|
58
|
+
]
|