ringo-task-queue 0.1.0.dev4__py3-none-win_amd64.whl → 0.1.0.dev6__py3-none-win_amd64.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.
@@ -1,71 +1,71 @@
1
- """Asyncio client for Ringo Task Queue."""
2
-
3
- from ._version import SDK_VERSION as __version__
4
- from .client import CompressionOption, LeasedTask, Ringo, RingoClient, TaskQueue
5
- from .concurrency import AdaptiveConcurrency, ResourceConcurrency
6
- from .errors import (
7
- ConflictError,
8
- DeadlineExceededError,
9
- DuplicateError,
10
- IncompatibleVersionError,
11
- InternalError,
12
- InvalidArgumentError,
13
- LeaseLostError,
14
- NotFoundError,
15
- PermanentTaskError,
16
- RetryTaskError,
17
- RingoError,
18
- UnavailableError,
19
- )
20
- from .models import (
21
- Attempt,
22
- BatchResult,
23
- EnqueueResult,
24
- LeaseInfo,
25
- PostgresStorage,
26
- Progress,
27
- RetryPolicy,
28
- RetryStrategy,
29
- SQLiteStorage,
30
- Task,
31
- TaskSpec,
32
- TaskStatus,
33
- )
34
- from .worker import TaskContext, Worker
35
-
36
- __all__ = [
37
- "AdaptiveConcurrency",
38
- "Attempt",
39
- "BatchResult",
40
- "CompressionOption",
41
- "ConflictError",
42
- "DeadlineExceededError",
43
- "DuplicateError",
44
- "EnqueueResult",
45
- "IncompatibleVersionError",
46
- "InternalError",
47
- "InvalidArgumentError",
48
- "LeaseInfo",
49
- "LeaseLostError",
50
- "LeasedTask",
51
- "NotFoundError",
52
- "PermanentTaskError",
53
- "PostgresStorage",
54
- "Progress",
55
- "ResourceConcurrency",
56
- "RetryPolicy",
57
- "RetryStrategy",
58
- "RetryTaskError",
59
- "Ringo",
60
- "RingoClient",
61
- "RingoError",
62
- "SQLiteStorage",
63
- "Task",
64
- "TaskContext",
65
- "TaskQueue",
66
- "TaskSpec",
67
- "TaskStatus",
68
- "UnavailableError",
69
- "Worker",
70
- "__version__",
71
- ]
1
+ """Asyncio client for Ringo Task Queue."""
2
+
3
+ from ._version import SDK_VERSION as __version__
4
+ from .client import CompressionOption, LeasedTask, Ringo, RingoClient, TaskQueue
5
+ from .concurrency import AdaptiveConcurrency, ResourceConcurrency
6
+ from .errors import (
7
+ ConflictError,
8
+ DeadlineExceededError,
9
+ DuplicateError,
10
+ IncompatibleVersionError,
11
+ InternalError,
12
+ InvalidArgumentError,
13
+ LeaseLostError,
14
+ NotFoundError,
15
+ PermanentTaskError,
16
+ RetryTaskError,
17
+ RingoError,
18
+ UnavailableError,
19
+ )
20
+ from .models import (
21
+ Attempt,
22
+ BatchResult,
23
+ EnqueueResult,
24
+ LeaseInfo,
25
+ PostgresStorage,
26
+ Progress,
27
+ RetryPolicy,
28
+ RetryStrategy,
29
+ SQLiteStorage,
30
+ Task,
31
+ TaskSpec,
32
+ TaskStatus,
33
+ )
34
+ from .worker import TaskContext, Worker
35
+
36
+ __all__ = [
37
+ "AdaptiveConcurrency",
38
+ "Attempt",
39
+ "BatchResult",
40
+ "CompressionOption",
41
+ "ConflictError",
42
+ "DeadlineExceededError",
43
+ "DuplicateError",
44
+ "EnqueueResult",
45
+ "IncompatibleVersionError",
46
+ "InternalError",
47
+ "InvalidArgumentError",
48
+ "LeaseInfo",
49
+ "LeaseLostError",
50
+ "LeasedTask",
51
+ "NotFoundError",
52
+ "PermanentTaskError",
53
+ "PostgresStorage",
54
+ "Progress",
55
+ "ResourceConcurrency",
56
+ "RetryPolicy",
57
+ "RetryStrategy",
58
+ "RetryTaskError",
59
+ "Ringo",
60
+ "RingoClient",
61
+ "RingoError",
62
+ "SQLiteStorage",
63
+ "Task",
64
+ "TaskContext",
65
+ "TaskQueue",
66
+ "TaskSpec",
67
+ "TaskStatus",
68
+ "UnavailableError",
69
+ "Worker",
70
+ "__version__",
71
+ ]
ringo_task_queue/_pb.py CHANGED
@@ -1,154 +1,154 @@
1
- """Conversions between frozen ``ringo.v1`` protobuf messages and Python values.
2
-
3
- This module is the single place that knows the wire shapes. It handles:
4
-
5
- - arbitrary JSON payloads (including an explicit ``None``) via
6
- ``google.protobuf.Value``;
7
- - timezone-aware UTC ``datetime`` <-> ``google.protobuf.Timestamp``;
8
- - ``datetime.timedelta`` <-> ``google.protobuf.Duration``.
9
- """
10
-
11
- from __future__ import annotations
12
-
13
- import math
14
- from datetime import datetime, timedelta, timezone
15
- from typing import Any
16
-
17
- from google.protobuf import duration_pb2, struct_pb2, timestamp_pb2
18
-
19
- from .errors import InvalidArgumentError
20
-
21
- #: Largest integer exactly representable in a proto ``double``/JSON number.
22
- _MAX_EXACT_INT = 2**53
23
-
24
- # ---------------------------------------------------------------------------
25
- # JSON values
26
-
27
-
28
- def py_to_value(obj: Any) -> struct_pb2.Value:
29
- """Convert an arbitrary JSON-compatible Python value to a proto Value.
30
-
31
- ``None`` becomes an explicit ``null_value`` (the proto contract requires a
32
- present payload, and JSON null is legal). Integers beyond the exact range
33
- of a proto ``double`` and non-finite floats are rejected instead of being
34
- silently corrupted.
35
- """
36
- msg = struct_pb2.Value()
37
- _fill_value(msg, obj)
38
- return msg
39
-
40
-
41
- def _fill_value(msg: struct_pb2.Value, obj: Any) -> None:
42
- if obj is None:
43
- msg.null_value = struct_pb2.NullValue.NULL_VALUE
44
- elif isinstance(obj, bool):
45
- msg.bool_value = obj
46
- elif isinstance(obj, int):
47
- if abs(obj) > _MAX_EXACT_INT:
48
- raise InvalidArgumentError(
49
- f"payload integer {obj} exceeds the exact JSON number range"
50
- f" (-2**53..2**53); store it as a string instead"
51
- )
52
- msg.number_value = float(obj)
53
- elif isinstance(obj, float):
54
- if not math.isfinite(obj):
55
- raise InvalidArgumentError(
56
- f"payload contains non-finite float {obj!r}; JSON numbers must be finite"
57
- )
58
- msg.number_value = obj
59
- elif isinstance(obj, str):
60
- msg.string_value = obj
61
- elif isinstance(obj, (list, tuple)):
62
- msg.list_value.SetInParent()
63
- for item in obj:
64
- _fill_value(msg.list_value.values.add(), item)
65
- elif isinstance(obj, dict):
66
- msg.struct_value.SetInParent()
67
- for key, item in obj.items():
68
- if not isinstance(key, str):
69
- raise InvalidArgumentError(
70
- f"payload object keys must be strings, got {type(key).__name__}"
71
- )
72
- _fill_value(msg.struct_value.fields[key], item)
73
- else:
74
- raise InvalidArgumentError(
75
- f"payload value of type {type(obj).__name__} is not JSON-serializable"
76
- )
77
-
78
-
79
- def value_to_py(msg: struct_pb2.Value) -> Any:
80
- """Convert a proto Value back to plain Python JSON values."""
81
- kind = msg.WhichOneof("kind")
82
- if kind is None or kind == "null_value":
83
- return None
84
- if kind == "bool_value":
85
- return msg.bool_value
86
- if kind == "string_value":
87
- return msg.string_value
88
- if kind == "number_value":
89
- number = msg.number_value
90
- # JSON has one numeric type; normalise integral doubles to int so
91
- # payloads round-trip through the SDK the way ``json`` users expect.
92
- if number.is_integer() and abs(number) <= _MAX_EXACT_INT:
93
- return int(number)
94
- return number
95
- if kind == "list_value":
96
- return [value_to_py(v) for v in msg.list_value.values]
97
- if kind == "struct_value":
98
- return {key: value_to_py(v) for key, v in msg.struct_value.fields.items()}
99
- raise InvalidArgumentError(f"unknown Value kind {kind!r}")
100
-
101
-
102
- # ---------------------------------------------------------------------------
103
- # Time
104
-
105
-
106
- def dt_to_ts(value: datetime) -> timestamp_pb2.Timestamp:
107
- if not isinstance(value, datetime):
108
- raise InvalidArgumentError(f"expected datetime, got {type(value).__name__}")
109
- if value.tzinfo is None:
110
- raise InvalidArgumentError(
111
- "datetime values must be timezone-aware; use datetime.UTC"
112
- )
113
- msg = timestamp_pb2.Timestamp()
114
- try:
115
- msg.FromDatetime(value)
116
- # FromDatetime is lenient about seconds; verify round-trip bounds.
117
- msg.ToDatetime(tzinfo=timezone.utc)
118
- except (ValueError, OverflowError) as exc:
119
- raise InvalidArgumentError(f"datetime out of Timestamp range: {exc}") from exc
120
- return msg
121
-
122
-
123
- def ts_to_dt(msg: timestamp_pb2.Timestamp) -> datetime:
124
- # ToDatetime returns a tz-aware UTC datetime.
125
- return msg.ToDatetime(tzinfo=timezone.utc)
126
-
127
-
128
- def td_to_dur(value: timedelta) -> duration_pb2.Duration:
129
- if not isinstance(value, timedelta):
130
- raise InvalidArgumentError(f"expected timedelta, got {type(value).__name__}")
131
- # The daemon/server represents durations as Go time.Duration (int64
132
- # nanoseconds, about +/-292 years); reject anything outside that range so
133
- # values can never silently wrap.
134
- total_ns = (
135
- (value.days * 86_400 + value.seconds) * 1_000_000 + value.microseconds
136
- ) * 1_000
137
- if abs(total_ns) > 2**63 - 1:
138
- raise InvalidArgumentError(
139
- f"timedelta {value} is outside the representable duration range"
140
- " (Go time.Duration, about +/-292 years)"
141
- )
142
- msg = duration_pb2.Duration()
143
- try:
144
- msg.FromNanoseconds(total_ns)
145
- msg.ToTimedelta()
146
- except (ValueError, OverflowError) as exc:
147
- raise InvalidArgumentError(f"timedelta out of Duration range: {exc}") from exc
148
- return msg
149
-
150
-
151
- def dur_to_td(msg: duration_pb2.Duration | None) -> timedelta | None:
152
- if msg is None:
153
- return None
154
- return msg.ToTimedelta()
1
+ """Conversions between frozen ``ringo.v1`` protobuf messages and Python values.
2
+
3
+ This module is the single place that knows the wire shapes. It handles:
4
+
5
+ - arbitrary JSON payloads (including an explicit ``None``) via
6
+ ``google.protobuf.Value``;
7
+ - timezone-aware UTC ``datetime`` <-> ``google.protobuf.Timestamp``;
8
+ - ``datetime.timedelta`` <-> ``google.protobuf.Duration``.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import math
14
+ from datetime import datetime, timedelta, timezone
15
+ from typing import Any
16
+
17
+ from google.protobuf import duration_pb2, struct_pb2, timestamp_pb2
18
+
19
+ from .errors import InvalidArgumentError
20
+
21
+ #: Largest integer exactly representable in a proto ``double``/JSON number.
22
+ _MAX_EXACT_INT = 2**53
23
+
24
+ # ---------------------------------------------------------------------------
25
+ # JSON values
26
+
27
+
28
+ def py_to_value(obj: Any) -> struct_pb2.Value:
29
+ """Convert an arbitrary JSON-compatible Python value to a proto Value.
30
+
31
+ ``None`` becomes an explicit ``null_value`` (the proto contract requires a
32
+ present payload, and JSON null is legal). Integers beyond the exact range
33
+ of a proto ``double`` and non-finite floats are rejected instead of being
34
+ silently corrupted.
35
+ """
36
+ msg = struct_pb2.Value()
37
+ _fill_value(msg, obj)
38
+ return msg
39
+
40
+
41
+ def _fill_value(msg: struct_pb2.Value, obj: Any) -> None:
42
+ if obj is None:
43
+ msg.null_value = struct_pb2.NullValue.NULL_VALUE
44
+ elif isinstance(obj, bool):
45
+ msg.bool_value = obj
46
+ elif isinstance(obj, int):
47
+ if abs(obj) > _MAX_EXACT_INT:
48
+ raise InvalidArgumentError(
49
+ f"payload integer {obj} exceeds the exact JSON number range"
50
+ f" (-2**53..2**53); store it as a string instead"
51
+ )
52
+ msg.number_value = float(obj)
53
+ elif isinstance(obj, float):
54
+ if not math.isfinite(obj):
55
+ raise InvalidArgumentError(
56
+ f"payload contains non-finite float {obj!r}; JSON numbers must be finite"
57
+ )
58
+ msg.number_value = obj
59
+ elif isinstance(obj, str):
60
+ msg.string_value = obj
61
+ elif isinstance(obj, (list, tuple)):
62
+ msg.list_value.SetInParent()
63
+ for item in obj:
64
+ _fill_value(msg.list_value.values.add(), item)
65
+ elif isinstance(obj, dict):
66
+ msg.struct_value.SetInParent()
67
+ for key, item in obj.items():
68
+ if not isinstance(key, str):
69
+ raise InvalidArgumentError(
70
+ f"payload object keys must be strings, got {type(key).__name__}"
71
+ )
72
+ _fill_value(msg.struct_value.fields[key], item)
73
+ else:
74
+ raise InvalidArgumentError(
75
+ f"payload value of type {type(obj).__name__} is not JSON-serializable"
76
+ )
77
+
78
+
79
+ def value_to_py(msg: struct_pb2.Value) -> Any:
80
+ """Convert a proto Value back to plain Python JSON values."""
81
+ kind = msg.WhichOneof("kind")
82
+ if kind is None or kind == "null_value":
83
+ return None
84
+ if kind == "bool_value":
85
+ return msg.bool_value
86
+ if kind == "string_value":
87
+ return msg.string_value
88
+ if kind == "number_value":
89
+ number = msg.number_value
90
+ # JSON has one numeric type; normalise integral doubles to int so
91
+ # payloads round-trip through the SDK the way ``json`` users expect.
92
+ if number.is_integer() and abs(number) <= _MAX_EXACT_INT:
93
+ return int(number)
94
+ return number
95
+ if kind == "list_value":
96
+ return [value_to_py(v) for v in msg.list_value.values]
97
+ if kind == "struct_value":
98
+ return {key: value_to_py(v) for key, v in msg.struct_value.fields.items()}
99
+ raise InvalidArgumentError(f"unknown Value kind {kind!r}")
100
+
101
+
102
+ # ---------------------------------------------------------------------------
103
+ # Time
104
+
105
+
106
+ def dt_to_ts(value: datetime) -> timestamp_pb2.Timestamp:
107
+ if not isinstance(value, datetime):
108
+ raise InvalidArgumentError(f"expected datetime, got {type(value).__name__}")
109
+ if value.tzinfo is None:
110
+ raise InvalidArgumentError(
111
+ "datetime values must be timezone-aware; use datetime.UTC"
112
+ )
113
+ msg = timestamp_pb2.Timestamp()
114
+ try:
115
+ msg.FromDatetime(value)
116
+ # FromDatetime is lenient about seconds; verify round-trip bounds.
117
+ msg.ToDatetime(tzinfo=timezone.utc)
118
+ except (ValueError, OverflowError) as exc:
119
+ raise InvalidArgumentError(f"datetime out of Timestamp range: {exc}") from exc
120
+ return msg
121
+
122
+
123
+ def ts_to_dt(msg: timestamp_pb2.Timestamp) -> datetime:
124
+ # ToDatetime returns a tz-aware UTC datetime.
125
+ return msg.ToDatetime(tzinfo=timezone.utc)
126
+
127
+
128
+ def td_to_dur(value: timedelta) -> duration_pb2.Duration:
129
+ if not isinstance(value, timedelta):
130
+ raise InvalidArgumentError(f"expected timedelta, got {type(value).__name__}")
131
+ # The daemon/server represents durations as Go time.Duration (int64
132
+ # nanoseconds, about +/-292 years); reject anything outside that range so
133
+ # values can never silently wrap.
134
+ total_ns = (
135
+ (value.days * 86_400 + value.seconds) * 1_000_000 + value.microseconds
136
+ ) * 1_000
137
+ if abs(total_ns) > 2**63 - 1:
138
+ raise InvalidArgumentError(
139
+ f"timedelta {value} is outside the representable duration range"
140
+ " (Go time.Duration, about +/-292 years)"
141
+ )
142
+ msg = duration_pb2.Duration()
143
+ try:
144
+ msg.FromNanoseconds(total_ns)
145
+ msg.ToTimedelta()
146
+ except (ValueError, OverflowError) as exc:
147
+ raise InvalidArgumentError(f"timedelta out of Duration range: {exc}") from exc
148
+ return msg
149
+
150
+
151
+ def dur_to_td(msg: duration_pb2.Duration | None) -> timedelta | None:
152
+ if msg is None:
153
+ return None
154
+ return msg.ToTimedelta()