threadify-sdk 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.
- threadify/__init__.py +51 -0
- threadify/client.py +191 -0
- threadify/connection.py +505 -0
- threadify/data_retriever.py +476 -0
- threadify/models.py +285 -0
- threadify/notification.py +164 -0
- threadify/otel_exporter.py +318 -0
- threadify/step.py +312 -0
- threadify/thread.py +323 -0
- threadify_sdk-0.2.0.dist-info/METADATA +181 -0
- threadify_sdk-0.2.0.dist-info/RECORD +14 -0
- threadify_sdk-0.2.0.dist-info/WHEEL +5 -0
- threadify_sdk-0.2.0.dist-info/licenses/LICENSE +21 -0
- threadify_sdk-0.2.0.dist-info/top_level.txt +1 -0
threadify/__init__.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from threadify.client import (
|
|
2
|
+
Threadify,
|
|
3
|
+
ThreadifyFactory,
|
|
4
|
+
)
|
|
5
|
+
from threadify.connection import Connection
|
|
6
|
+
from threadify.data_retriever import ArchivedStep, ArchivedThread, DataRetriever
|
|
7
|
+
from threadify.models import (
|
|
8
|
+
CompleteDataOptions,
|
|
9
|
+
ConnectOptions,
|
|
10
|
+
HistoryQueryOptions,
|
|
11
|
+
InviteOptions,
|
|
12
|
+
InviteResponse,
|
|
13
|
+
NotificationData,
|
|
14
|
+
RefQuery,
|
|
15
|
+
StepResult,
|
|
16
|
+
SubStepData,
|
|
17
|
+
ThreadEndResponse,
|
|
18
|
+
WaitOptions,
|
|
19
|
+
)
|
|
20
|
+
from threadify.notification import Notification
|
|
21
|
+
from threadify.otel_exporter import ThreadifySpanExporter
|
|
22
|
+
from threadify.step import DuplicateStepError, ThreadStep, is_duplicate_error
|
|
23
|
+
from threadify.thread import ThreadInstance
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
"Threadify",
|
|
27
|
+
"ThreadifyFactory",
|
|
28
|
+
"Connection",
|
|
29
|
+
"ThreadInstance",
|
|
30
|
+
"ThreadStep",
|
|
31
|
+
"DuplicateStepError",
|
|
32
|
+
"is_duplicate_error",
|
|
33
|
+
"Notification",
|
|
34
|
+
"DataRetriever",
|
|
35
|
+
"ArchivedThread",
|
|
36
|
+
"ArchivedStep",
|
|
37
|
+
"ThreadifySpanExporter",
|
|
38
|
+
"ConnectOptions",
|
|
39
|
+
"StepResult",
|
|
40
|
+
"SubStepData",
|
|
41
|
+
"InviteOptions",
|
|
42
|
+
"InviteResponse",
|
|
43
|
+
"ThreadEndResponse",
|
|
44
|
+
"WaitOptions",
|
|
45
|
+
"NotificationData",
|
|
46
|
+
"RefQuery",
|
|
47
|
+
"CompleteDataOptions",
|
|
48
|
+
"HistoryQueryOptions",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
__version__ = "0.1.0"
|
threadify/client.py
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import json
|
|
5
|
+
import logging
|
|
6
|
+
from dataclasses import fields
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
import websockets
|
|
10
|
+
|
|
11
|
+
from threadify.connection import Connection
|
|
12
|
+
from threadify.models import (
|
|
13
|
+
ACTION_CONNECT,
|
|
14
|
+
FIELD_ACTION,
|
|
15
|
+
FIELD_API_KEY,
|
|
16
|
+
FIELD_MAX_IN_FLIGHT,
|
|
17
|
+
FIELD_MESSAGE,
|
|
18
|
+
FIELD_SERVICE_NAME,
|
|
19
|
+
FIELD_STATUS,
|
|
20
|
+
STATUS_SUCCESS,
|
|
21
|
+
ConnectOptions,
|
|
22
|
+
require_non_empty,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _copy_connect_options(src: ConnectOptions) -> ConnectOptions:
|
|
27
|
+
data = {f.name: getattr(src, f.name) for f in fields(ConnectOptions)}
|
|
28
|
+
return ConnectOptions(**data)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _build_connect_options(
|
|
32
|
+
*,
|
|
33
|
+
base: ConnectOptions | None,
|
|
34
|
+
service_name: str | None,
|
|
35
|
+
ws_url: str | None,
|
|
36
|
+
graphql_url: str | None,
|
|
37
|
+
debug: bool | None,
|
|
38
|
+
max_in_flight: int | None,
|
|
39
|
+
connect_timeout: float | None,
|
|
40
|
+
logger: logging.Logger | None = None,
|
|
41
|
+
) -> ConnectOptions:
|
|
42
|
+
cfg = _copy_connect_options(base) if base else ConnectOptions()
|
|
43
|
+
|
|
44
|
+
if service_name is not None:
|
|
45
|
+
cfg.service_name = service_name
|
|
46
|
+
if ws_url is not None:
|
|
47
|
+
cfg.ws_url = ws_url
|
|
48
|
+
if graphql_url is not None:
|
|
49
|
+
cfg.graphql_url = graphql_url
|
|
50
|
+
if debug is not None:
|
|
51
|
+
cfg.debug = debug
|
|
52
|
+
if max_in_flight is not None:
|
|
53
|
+
cfg.max_in_flight = max_in_flight
|
|
54
|
+
if connect_timeout is not None:
|
|
55
|
+
cfg.connect_timeout = connect_timeout
|
|
56
|
+
if logger is not None:
|
|
57
|
+
cfg.logger = logger
|
|
58
|
+
|
|
59
|
+
cfg.with_defaults()
|
|
60
|
+
cfg.validate()
|
|
61
|
+
return cfg
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class Threadify:
|
|
65
|
+
"""Factory for creating Threadify connections."""
|
|
66
|
+
|
|
67
|
+
@staticmethod
|
|
68
|
+
async def connect(
|
|
69
|
+
api_key: str,
|
|
70
|
+
*args: Any,
|
|
71
|
+
service_name: str | None = None,
|
|
72
|
+
ws_url: str | None = None,
|
|
73
|
+
graphql_url: str | None = None,
|
|
74
|
+
debug: bool | None = None,
|
|
75
|
+
max_in_flight: int | None = None,
|
|
76
|
+
connect_timeout: float | None = None,
|
|
77
|
+
logger: logging.Logger | None = None,
|
|
78
|
+
options: ConnectOptions | None = None,
|
|
79
|
+
) -> Connection:
|
|
80
|
+
require_non_empty("api_key", api_key)
|
|
81
|
+
|
|
82
|
+
legacy_service_name: str | None = None
|
|
83
|
+
legacy_config: ConnectOptions | None = None
|
|
84
|
+
for arg in args:
|
|
85
|
+
if isinstance(arg, str) and legacy_service_name is None:
|
|
86
|
+
legacy_service_name = arg
|
|
87
|
+
continue
|
|
88
|
+
if isinstance(arg, ConnectOptions) and legacy_config is None:
|
|
89
|
+
legacy_config = arg
|
|
90
|
+
continue
|
|
91
|
+
raise TypeError(
|
|
92
|
+
"invalid connect argument; expected service_name (str) or ConnectOptions"
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
cfg = _build_connect_options(
|
|
96
|
+
base=options or legacy_config,
|
|
97
|
+
service_name=service_name if service_name is not None else legacy_service_name,
|
|
98
|
+
ws_url=ws_url,
|
|
99
|
+
graphql_url=graphql_url,
|
|
100
|
+
debug=debug,
|
|
101
|
+
max_in_flight=max_in_flight,
|
|
102
|
+
connect_timeout=connect_timeout,
|
|
103
|
+
logger=logger,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
ws = await asyncio.wait_for(
|
|
107
|
+
websockets.connect(cfg.ws_url),
|
|
108
|
+
timeout=cfg.connect_timeout,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
connect_msg = {
|
|
112
|
+
FIELD_ACTION: ACTION_CONNECT,
|
|
113
|
+
FIELD_API_KEY: api_key,
|
|
114
|
+
FIELD_SERVICE_NAME: cfg.service_name,
|
|
115
|
+
FIELD_MAX_IN_FLIGHT: cfg.max_in_flight,
|
|
116
|
+
}
|
|
117
|
+
await ws.send(json.dumps(connect_msg))
|
|
118
|
+
|
|
119
|
+
raw = await asyncio.wait_for(ws.recv(), timeout=cfg.connect_timeout)
|
|
120
|
+
resp = json.loads(raw)
|
|
121
|
+
|
|
122
|
+
if resp.get(FIELD_ACTION) != ACTION_CONNECT or resp.get(FIELD_STATUS) != STATUS_SUCCESS:
|
|
123
|
+
await ws.close()
|
|
124
|
+
msg = resp.get(FIELD_MESSAGE, "connection failed")
|
|
125
|
+
raise ConnectionError(msg)
|
|
126
|
+
|
|
127
|
+
conn = Connection(
|
|
128
|
+
ws=ws,
|
|
129
|
+
api_key=api_key,
|
|
130
|
+
service_name=cfg.service_name,
|
|
131
|
+
graphql_url=cfg.graphql_url,
|
|
132
|
+
debug=cfg.debug,
|
|
133
|
+
max_in_flight=cfg.max_in_flight,
|
|
134
|
+
logger=cfg.logger,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
return conn
|
|
138
|
+
|
|
139
|
+
@staticmethod
|
|
140
|
+
def create(
|
|
141
|
+
api_key: str,
|
|
142
|
+
*args: Any,
|
|
143
|
+
service_name: str | None = None,
|
|
144
|
+
ws_url: str | None = None,
|
|
145
|
+
graphql_url: str | None = None,
|
|
146
|
+
debug: bool | None = None,
|
|
147
|
+
max_in_flight: int | None = None,
|
|
148
|
+
connect_timeout: float | None = None,
|
|
149
|
+
logger: logging.Logger | None = None,
|
|
150
|
+
options: ConnectOptions | None = None,
|
|
151
|
+
) -> ThreadifyFactory:
|
|
152
|
+
legacy_service_name: str | None = None
|
|
153
|
+
legacy_config: ConnectOptions | None = None
|
|
154
|
+
for arg in args:
|
|
155
|
+
if isinstance(arg, str) and legacy_service_name is None:
|
|
156
|
+
legacy_service_name = arg
|
|
157
|
+
continue
|
|
158
|
+
if isinstance(arg, ConnectOptions) and legacy_config is None:
|
|
159
|
+
legacy_config = arg
|
|
160
|
+
continue
|
|
161
|
+
raise TypeError(
|
|
162
|
+
"invalid create argument; expected service_name (str) or ConnectOptions"
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
cfg = _build_connect_options(
|
|
166
|
+
base=options or legacy_config,
|
|
167
|
+
service_name=service_name if service_name is not None else legacy_service_name,
|
|
168
|
+
ws_url=ws_url,
|
|
169
|
+
graphql_url=graphql_url,
|
|
170
|
+
debug=debug,
|
|
171
|
+
max_in_flight=max_in_flight,
|
|
172
|
+
connect_timeout=connect_timeout,
|
|
173
|
+
logger=logger,
|
|
174
|
+
)
|
|
175
|
+
return ThreadifyFactory(
|
|
176
|
+
api_key=api_key,
|
|
177
|
+
options=cfg,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class ThreadifyFactory:
|
|
182
|
+
def __init__(
|
|
183
|
+
self,
|
|
184
|
+
api_key: str,
|
|
185
|
+
options: ConnectOptions,
|
|
186
|
+
):
|
|
187
|
+
self._api_key = api_key
|
|
188
|
+
self._options = _copy_connect_options(options)
|
|
189
|
+
|
|
190
|
+
async def connect(self) -> Connection:
|
|
191
|
+
return await Threadify.connect(self._api_key, options=self._options)
|