trismik 0.9.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.
- trismik/__init__.py +20 -0
- trismik/_mapper.py +79 -0
- trismik/_utils.py +44 -0
- trismik/client.py +274 -0
- trismik/client_async.py +280 -0
- trismik/exceptions.py +13 -0
- trismik/runner.py +85 -0
- trismik/runner_async.py +87 -0
- trismik/types.py +133 -0
- trismik-0.9.0.dist-info/LICENSE +21 -0
- trismik-0.9.0.dist-info/METADATA +60 -0
- trismik-0.9.0.dist-info/RECORD +13 -0
- trismik-0.9.0.dist-info/WHEEL +4 -0
trismik/__init__.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from .client import TrismikClient
|
|
2
|
+
from .client_async import TrismikAsyncClient
|
|
3
|
+
from .exceptions import (
|
|
4
|
+
TrismikError,
|
|
5
|
+
TrismikApiError
|
|
6
|
+
)
|
|
7
|
+
from .runner import TrismikRunner
|
|
8
|
+
from .runner_async import TrismikAsyncRunner
|
|
9
|
+
from .types import (
|
|
10
|
+
TrismikTest,
|
|
11
|
+
TrismikAuth,
|
|
12
|
+
TrismikSession,
|
|
13
|
+
TrismikItem,
|
|
14
|
+
TrismikMultipleChoiceTextItem,
|
|
15
|
+
TrismikChoice,
|
|
16
|
+
TrismikTextChoice,
|
|
17
|
+
TrismikResult,
|
|
18
|
+
TrismikResponse,
|
|
19
|
+
TrismikResultsAndResponses,
|
|
20
|
+
)
|
trismik/_mapper.py
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
from typing import List, Any
|
|
2
|
+
|
|
3
|
+
from dateutil.parser import parse as parse_date
|
|
4
|
+
|
|
5
|
+
from .exceptions import TrismikApiError
|
|
6
|
+
from .types import (
|
|
7
|
+
TrismikItem,
|
|
8
|
+
TrismikResult,
|
|
9
|
+
TrismikMultipleChoiceTextItem,
|
|
10
|
+
TrismikTextChoice,
|
|
11
|
+
TrismikAuth,
|
|
12
|
+
TrismikTest,
|
|
13
|
+
TrismikSession,
|
|
14
|
+
TrismikResponse,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TrismikResponseMapper:
|
|
19
|
+
|
|
20
|
+
@staticmethod
|
|
21
|
+
def to_auth(json: dict[str, Any]) -> TrismikAuth:
|
|
22
|
+
return TrismikAuth(
|
|
23
|
+
token=json["token"],
|
|
24
|
+
expires=parse_date(json["expires"]),
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
def to_tests(json: List[dict[str, Any]]) -> List[TrismikTest]:
|
|
29
|
+
return [
|
|
30
|
+
TrismikTest(
|
|
31
|
+
id=item["id"],
|
|
32
|
+
name=item["name"],
|
|
33
|
+
) for item in json
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
@staticmethod
|
|
37
|
+
def to_session(json: dict[str, Any]) -> TrismikSession:
|
|
38
|
+
return TrismikSession(
|
|
39
|
+
id=json["id"],
|
|
40
|
+
url=json["url"],
|
|
41
|
+
status=json["status"],
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
@staticmethod
|
|
45
|
+
def to_item(json: dict[str, Any]) -> TrismikItem:
|
|
46
|
+
if json["type"] == "multiple_choice_text":
|
|
47
|
+
return TrismikMultipleChoiceTextItem(
|
|
48
|
+
id=json["id"],
|
|
49
|
+
question=json["question"],
|
|
50
|
+
choices=[
|
|
51
|
+
TrismikTextChoice(
|
|
52
|
+
id=choice["id"],
|
|
53
|
+
text=choice["text"],
|
|
54
|
+
) for choice in json["choices"]
|
|
55
|
+
]
|
|
56
|
+
)
|
|
57
|
+
else:
|
|
58
|
+
raise TrismikApiError(
|
|
59
|
+
f"API has returned unrecognized item type: {json['type']}")
|
|
60
|
+
|
|
61
|
+
@staticmethod
|
|
62
|
+
def to_results(json: List[dict[str, Any]]) -> List[TrismikResult]:
|
|
63
|
+
return [
|
|
64
|
+
TrismikResult(
|
|
65
|
+
trait=item["trait"],
|
|
66
|
+
name=item["name"],
|
|
67
|
+
value=item["value"],
|
|
68
|
+
) for item in json
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
@staticmethod
|
|
72
|
+
def to_responses(json: List[dict[str, Any]]) -> List[TrismikResponse]:
|
|
73
|
+
return [
|
|
74
|
+
TrismikResponse(
|
|
75
|
+
item_id=response["itemId"],
|
|
76
|
+
value=response["value"],
|
|
77
|
+
score=response["score"],
|
|
78
|
+
) for response in json
|
|
79
|
+
]
|
trismik/_utils.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
import httpx
|
|
4
|
+
|
|
5
|
+
from .exceptions import TrismikError
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TrismikUtils:
|
|
9
|
+
|
|
10
|
+
@staticmethod
|
|
11
|
+
def get_error_message(response: httpx.Response) -> str:
|
|
12
|
+
try:
|
|
13
|
+
return (response.json()).get("message", "Unknown error")
|
|
14
|
+
except (httpx.RequestError, ValueError):
|
|
15
|
+
error_message = response.content.decode("utf-8", errors="ignore")
|
|
16
|
+
return error_message
|
|
17
|
+
|
|
18
|
+
@staticmethod
|
|
19
|
+
def required_option(
|
|
20
|
+
value: str | None,
|
|
21
|
+
name: str,
|
|
22
|
+
env: str
|
|
23
|
+
) -> str:
|
|
24
|
+
if value is None:
|
|
25
|
+
value = os.environ.get(env)
|
|
26
|
+
if value is None:
|
|
27
|
+
raise TrismikError(
|
|
28
|
+
f"The {name} client option must be set either by passing "
|
|
29
|
+
f"{env} to the client or by setting the {env} "
|
|
30
|
+
"environment variable"
|
|
31
|
+
)
|
|
32
|
+
return value
|
|
33
|
+
|
|
34
|
+
@staticmethod
|
|
35
|
+
def option(
|
|
36
|
+
value: str | None,
|
|
37
|
+
default: str,
|
|
38
|
+
env: str,
|
|
39
|
+
) -> str:
|
|
40
|
+
if value is None:
|
|
41
|
+
value = os.environ.get(env)
|
|
42
|
+
if value is None:
|
|
43
|
+
return default
|
|
44
|
+
return value
|
trismik/client.py
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
from typing import List, Any, Optional
|
|
2
|
+
|
|
3
|
+
import httpx
|
|
4
|
+
|
|
5
|
+
from ._mapper import TrismikResponseMapper
|
|
6
|
+
from ._utils import TrismikUtils
|
|
7
|
+
from .exceptions import TrismikApiError
|
|
8
|
+
from .types import (
|
|
9
|
+
TrismikTest,
|
|
10
|
+
TrismikAuth,
|
|
11
|
+
TrismikSession,
|
|
12
|
+
TrismikItem,
|
|
13
|
+
TrismikResult,
|
|
14
|
+
TrismikResponse,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TrismikClient:
|
|
19
|
+
_serviceUrl: str = "https://trismik.e-psychometrics.com/api"
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
service_url: Optional[str] = None,
|
|
24
|
+
api_key: Optional[str] = None,
|
|
25
|
+
http_client: Optional[httpx.Client] | None = None,
|
|
26
|
+
) -> None:
|
|
27
|
+
"""
|
|
28
|
+
Initializes a new Trismik client.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
service_url (Optional[str]): URL of the Trismik service.
|
|
32
|
+
api_key (Optional[str]): API key for the Trismik service.
|
|
33
|
+
http_client (Optional[httpx.Client]): HTTP client to use for requests.
|
|
34
|
+
|
|
35
|
+
Raises:
|
|
36
|
+
TrismikError: If service_url or api_key are not provided and not found in environment.
|
|
37
|
+
TrismikApiError: If API request fails.
|
|
38
|
+
"""
|
|
39
|
+
self._service_url = TrismikUtils.option(
|
|
40
|
+
service_url, self._serviceUrl, "TRISMIK_SERVICE_URL"
|
|
41
|
+
)
|
|
42
|
+
self._api_key = TrismikUtils.required_option(
|
|
43
|
+
api_key, "api_key", "TRISMIK_API_KEY"
|
|
44
|
+
)
|
|
45
|
+
self._http_client = http_client or httpx.Client(
|
|
46
|
+
base_url=self._service_url)
|
|
47
|
+
|
|
48
|
+
def authenticate(self) -> TrismikAuth:
|
|
49
|
+
"""
|
|
50
|
+
Authenticates with the Trismik service.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
TrismikAuth: Authentication token.
|
|
54
|
+
|
|
55
|
+
Raises:
|
|
56
|
+
TrismikApiError: If API request fails.
|
|
57
|
+
"""
|
|
58
|
+
try:
|
|
59
|
+
url = "/client/auth"
|
|
60
|
+
body = {"apiKey": self._api_key}
|
|
61
|
+
response = self._http_client.post(url, json=body)
|
|
62
|
+
response.raise_for_status()
|
|
63
|
+
json = response.json()
|
|
64
|
+
return TrismikResponseMapper.to_auth(json)
|
|
65
|
+
except httpx.HTTPStatusError as e:
|
|
66
|
+
raise TrismikApiError(
|
|
67
|
+
TrismikUtils.get_error_message(e.response)) from e
|
|
68
|
+
except httpx.HTTPError as e:
|
|
69
|
+
raise TrismikApiError(str(e)) from e
|
|
70
|
+
|
|
71
|
+
def refresh_token(self, token: str) -> TrismikAuth:
|
|
72
|
+
"""
|
|
73
|
+
Refreshes the authentication token.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
token (str): Current authentication token.
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
TrismikAuth: New authentication token.
|
|
80
|
+
|
|
81
|
+
Raises:
|
|
82
|
+
TrismikApiError: If API request fails.
|
|
83
|
+
"""
|
|
84
|
+
try:
|
|
85
|
+
url = "/client/token"
|
|
86
|
+
headers = {"Authorization": f"Bearer {token}"}
|
|
87
|
+
response = self._http_client.get(url, headers=headers)
|
|
88
|
+
response.raise_for_status()
|
|
89
|
+
json = response.json()
|
|
90
|
+
return TrismikResponseMapper.to_auth(json)
|
|
91
|
+
except httpx.HTTPStatusError as e:
|
|
92
|
+
raise TrismikApiError(
|
|
93
|
+
TrismikUtils.get_error_message(e.response)) from e
|
|
94
|
+
except httpx.HTTPError as e:
|
|
95
|
+
raise TrismikApiError(str(e)) from e
|
|
96
|
+
|
|
97
|
+
def available_tests(self, token: str) -> List[TrismikTest]:
|
|
98
|
+
"""
|
|
99
|
+
Retrieves a list of available tests.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
token (str): Authentication token.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
List[TrismikTest]: List of available tests.
|
|
106
|
+
|
|
107
|
+
Raises:
|
|
108
|
+
TrismikApiError: If API request fails.
|
|
109
|
+
"""
|
|
110
|
+
try:
|
|
111
|
+
url = "/client/tests"
|
|
112
|
+
headers = {"Authorization": f"Bearer {token}"}
|
|
113
|
+
response = self._http_client.get(url, headers=headers)
|
|
114
|
+
response.raise_for_status()
|
|
115
|
+
json = response.json()
|
|
116
|
+
return TrismikResponseMapper.to_tests(json)
|
|
117
|
+
except httpx.HTTPStatusError as e:
|
|
118
|
+
raise TrismikApiError(
|
|
119
|
+
TrismikUtils.get_error_message(e.response)) from e
|
|
120
|
+
except httpx.HTTPError as e:
|
|
121
|
+
raise TrismikApiError(str(e)) from e
|
|
122
|
+
|
|
123
|
+
def create_session(self, test_id: str, token: str) -> TrismikSession:
|
|
124
|
+
"""
|
|
125
|
+
Creates a new session for a test.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
test_id (str): ID of the test.
|
|
129
|
+
token (str): Authentication token.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
TrismikSession: New session
|
|
133
|
+
|
|
134
|
+
Raises:
|
|
135
|
+
TrismikApiError: If API request fails.
|
|
136
|
+
"""
|
|
137
|
+
try:
|
|
138
|
+
url = "/client/sessions"
|
|
139
|
+
headers = {"Authorization": f"Bearer {token}"}
|
|
140
|
+
body = {"testId": test_id, }
|
|
141
|
+
response = self._http_client.post(url, headers=headers, json=body)
|
|
142
|
+
response.raise_for_status()
|
|
143
|
+
json = response.json()
|
|
144
|
+
return TrismikResponseMapper.to_session(json)
|
|
145
|
+
except httpx.HTTPStatusError as e:
|
|
146
|
+
raise TrismikApiError(
|
|
147
|
+
TrismikUtils.get_error_message(e.response)) from e
|
|
148
|
+
except httpx.HTTPError as e:
|
|
149
|
+
raise TrismikApiError(str(e)) from e
|
|
150
|
+
|
|
151
|
+
def current_item(
|
|
152
|
+
self,
|
|
153
|
+
session_url: str,
|
|
154
|
+
token: str
|
|
155
|
+
) -> TrismikItem:
|
|
156
|
+
"""
|
|
157
|
+
Retrieves the current test item.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
session_url (str): URL of the session.
|
|
161
|
+
token (str): Authentication token.
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
TrismikItem: Current test item.
|
|
165
|
+
|
|
166
|
+
Raises:
|
|
167
|
+
TrismikApiError: If API request fails.
|
|
168
|
+
"""
|
|
169
|
+
try:
|
|
170
|
+
url = f"{session_url}/item"
|
|
171
|
+
headers = {"Authorization": f"Bearer {token}"}
|
|
172
|
+
response = self._http_client.get(url, headers=headers)
|
|
173
|
+
response.raise_for_status()
|
|
174
|
+
json = response.json()
|
|
175
|
+
return TrismikResponseMapper.to_item(json)
|
|
176
|
+
except httpx.HTTPStatusError as e:
|
|
177
|
+
raise TrismikApiError(
|
|
178
|
+
TrismikUtils.get_error_message(e.response)) from e
|
|
179
|
+
except httpx.HTTPError as e:
|
|
180
|
+
raise TrismikApiError(str(e)) from e
|
|
181
|
+
|
|
182
|
+
def respond_to_current_item(
|
|
183
|
+
self,
|
|
184
|
+
session_url: str,
|
|
185
|
+
value: Any,
|
|
186
|
+
token: str
|
|
187
|
+
) -> TrismikItem | None:
|
|
188
|
+
"""
|
|
189
|
+
Responds to the current test item.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
session_url (str): URL of the session.
|
|
193
|
+
value (Any): Response value.
|
|
194
|
+
token (str): Authentication token.
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
TrismikItem | None: Next test item or None if session is finished.
|
|
198
|
+
|
|
199
|
+
Raises:
|
|
200
|
+
TrismikApiError: If API request fails.
|
|
201
|
+
"""
|
|
202
|
+
try:
|
|
203
|
+
url = f"{session_url}/item"
|
|
204
|
+
body = {"value": value}
|
|
205
|
+
headers = {"Authorization": f"Bearer {token}"}
|
|
206
|
+
response = self._http_client.post(url, headers=headers, json=body)
|
|
207
|
+
response.raise_for_status()
|
|
208
|
+
if response.status_code == 204:
|
|
209
|
+
return None
|
|
210
|
+
else:
|
|
211
|
+
json = response.json()
|
|
212
|
+
return TrismikResponseMapper.to_item(json)
|
|
213
|
+
except httpx.HTTPStatusError as e:
|
|
214
|
+
raise TrismikApiError(
|
|
215
|
+
TrismikUtils.get_error_message(e.response)) from e
|
|
216
|
+
except httpx.HTTPError as e:
|
|
217
|
+
raise TrismikApiError(str(e)) from e
|
|
218
|
+
|
|
219
|
+
def results(self, session_url: str, token: str) -> List[TrismikResult]:
|
|
220
|
+
"""
|
|
221
|
+
Retrieves the results of a session.
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
session_url (str): URL of the session.
|
|
225
|
+
token (str): Authentication token.
|
|
226
|
+
|
|
227
|
+
Returns:
|
|
228
|
+
List[TrismikResult]: Results of the session.
|
|
229
|
+
|
|
230
|
+
Raises:
|
|
231
|
+
TrismikApiError: If API request fails.
|
|
232
|
+
"""
|
|
233
|
+
try:
|
|
234
|
+
url = f"{session_url}/results"
|
|
235
|
+
headers = {"Authorization": f"Bearer {token}"}
|
|
236
|
+
response = self._http_client.get(url, headers=headers)
|
|
237
|
+
response.raise_for_status()
|
|
238
|
+
json = response.json()
|
|
239
|
+
return TrismikResponseMapper.to_results(json)
|
|
240
|
+
except httpx.HTTPStatusError as e:
|
|
241
|
+
raise TrismikApiError(
|
|
242
|
+
TrismikUtils.get_error_message(e.response)) from e
|
|
243
|
+
except httpx.HTTPError as e:
|
|
244
|
+
raise TrismikApiError(str(e)) from e
|
|
245
|
+
|
|
246
|
+
def responses(self,
|
|
247
|
+
session_url: str,
|
|
248
|
+
token: str
|
|
249
|
+
) -> List[TrismikResponse]:
|
|
250
|
+
"""
|
|
251
|
+
Retrieves responses to session items.
|
|
252
|
+
|
|
253
|
+
Args:
|
|
254
|
+
session_url (str): URL of the session.
|
|
255
|
+
token (str): Authentication token.
|
|
256
|
+
|
|
257
|
+
Returns:
|
|
258
|
+
List[TrismikResponse]: Responses of the session.
|
|
259
|
+
|
|
260
|
+
Raises:
|
|
261
|
+
TrismikApiError: If API request fails.
|
|
262
|
+
"""
|
|
263
|
+
try:
|
|
264
|
+
url = f"{session_url}/responses"
|
|
265
|
+
headers = {"Authorization": f"Bearer {token}"}
|
|
266
|
+
response = self._http_client.get(url, headers=headers)
|
|
267
|
+
response.raise_for_status()
|
|
268
|
+
json = response.json()
|
|
269
|
+
return TrismikResponseMapper.to_responses(json)
|
|
270
|
+
except httpx.HTTPStatusError as e:
|
|
271
|
+
raise TrismikApiError(
|
|
272
|
+
TrismikUtils.get_error_message(e.response)) from e
|
|
273
|
+
except httpx.HTTPError as e:
|
|
274
|
+
raise TrismikApiError(str(e)) from e
|
trismik/client_async.py
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
from typing import List, Any, Optional
|
|
2
|
+
|
|
3
|
+
import httpx
|
|
4
|
+
|
|
5
|
+
from ._mapper import TrismikResponseMapper
|
|
6
|
+
from ._utils import TrismikUtils
|
|
7
|
+
from .exceptions import TrismikApiError
|
|
8
|
+
from .types import (
|
|
9
|
+
TrismikTest,
|
|
10
|
+
TrismikAuth,
|
|
11
|
+
TrismikSession,
|
|
12
|
+
TrismikItem,
|
|
13
|
+
TrismikResult,
|
|
14
|
+
TrismikResponse,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TrismikAsyncClient:
|
|
19
|
+
_serviceUrl: str = "https://trismik.e-psychometrics.com/api"
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
service_url: Optional[str] = None,
|
|
24
|
+
api_key: Optional[str] = None,
|
|
25
|
+
http_client: Optional[httpx.AsyncClient] | None = None,
|
|
26
|
+
) -> None:
|
|
27
|
+
"""
|
|
28
|
+
Initializes a new Trismik client (async version).
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
service_url (Optional[str]): URL of the Trismik service.
|
|
32
|
+
api_key (Optional[str]): API key for the Trismik service.
|
|
33
|
+
http_client (Optional[httpx.Client]): HTTP client to use for requests.
|
|
34
|
+
|
|
35
|
+
Raises:
|
|
36
|
+
TrismikError: If service_url or api_key are not provided and not found in environment.
|
|
37
|
+
TrismikApiError: If API request fails.
|
|
38
|
+
"""
|
|
39
|
+
self._service_url = TrismikUtils.option(
|
|
40
|
+
service_url, self._serviceUrl, "TRISMIK_SERVICE_URL"
|
|
41
|
+
)
|
|
42
|
+
self._api_key = TrismikUtils.required_option(
|
|
43
|
+
api_key, "api_key", "TRISMIK_API_KEY"
|
|
44
|
+
)
|
|
45
|
+
self._http_client = http_client or httpx.AsyncClient(
|
|
46
|
+
base_url=self._service_url)
|
|
47
|
+
|
|
48
|
+
async def authenticate(self) -> TrismikAuth:
|
|
49
|
+
"""
|
|
50
|
+
Authenticates with the Trismik service.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
TrismikAuth: Authentication token.
|
|
54
|
+
|
|
55
|
+
Raises:
|
|
56
|
+
TrismikApiError: If API request fails.
|
|
57
|
+
"""
|
|
58
|
+
try:
|
|
59
|
+
url = "/client/auth"
|
|
60
|
+
body = {"apiKey": self._api_key}
|
|
61
|
+
response = await self._http_client.post(url, json=body)
|
|
62
|
+
response.raise_for_status()
|
|
63
|
+
json = response.json()
|
|
64
|
+
return TrismikResponseMapper.to_auth(json)
|
|
65
|
+
except httpx.HTTPStatusError as e:
|
|
66
|
+
raise TrismikApiError(
|
|
67
|
+
TrismikUtils.get_error_message(e.response)) from e
|
|
68
|
+
except httpx.HTTPError as e:
|
|
69
|
+
raise TrismikApiError(str(e)) from e
|
|
70
|
+
|
|
71
|
+
async def refresh_token(self, token: str) -> TrismikAuth:
|
|
72
|
+
"""
|
|
73
|
+
Refreshes the authentication token.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
token (str): Current authentication token.
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
TrismikAuth: New authentication token.
|
|
80
|
+
|
|
81
|
+
Raises:
|
|
82
|
+
TrismikApiError: If API request fails.
|
|
83
|
+
"""
|
|
84
|
+
try:
|
|
85
|
+
url = "/client/token"
|
|
86
|
+
headers = {"Authorization": f"Bearer {token}"}
|
|
87
|
+
response = await self._http_client.get(url, headers=headers)
|
|
88
|
+
response.raise_for_status()
|
|
89
|
+
json = response.json()
|
|
90
|
+
return TrismikResponseMapper.to_auth(json)
|
|
91
|
+
except httpx.HTTPStatusError as e:
|
|
92
|
+
raise TrismikApiError(
|
|
93
|
+
TrismikUtils.get_error_message(e.response)) from e
|
|
94
|
+
except httpx.HTTPError as e:
|
|
95
|
+
raise TrismikApiError(str(e)) from e
|
|
96
|
+
|
|
97
|
+
async def available_tests(self, token: str) -> List[TrismikTest]:
|
|
98
|
+
"""
|
|
99
|
+
Retrieves a list of available tests.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
token (str): Authentication token.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
List[TrismikTest]: List of available tests.
|
|
106
|
+
|
|
107
|
+
Raises:
|
|
108
|
+
TrismikApiError: If API request fails.
|
|
109
|
+
"""
|
|
110
|
+
try:
|
|
111
|
+
url = "/client/tests"
|
|
112
|
+
headers = {"Authorization": f"Bearer {token}"}
|
|
113
|
+
response = await self._http_client.get(url, headers=headers)
|
|
114
|
+
response.raise_for_status()
|
|
115
|
+
json = response.json()
|
|
116
|
+
return TrismikResponseMapper.to_tests(json)
|
|
117
|
+
except httpx.HTTPStatusError as e:
|
|
118
|
+
raise TrismikApiError(
|
|
119
|
+
TrismikUtils.get_error_message(e.response)) from e
|
|
120
|
+
except httpx.HTTPError as e:
|
|
121
|
+
raise TrismikApiError(str(e)) from e
|
|
122
|
+
|
|
123
|
+
async def create_session(self, test_id: str, token: str) -> TrismikSession:
|
|
124
|
+
"""
|
|
125
|
+
Creates a new session for a test.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
test_id (str): ID of the test.
|
|
129
|
+
token (str): Authentication token.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
TrismikSession: New session
|
|
133
|
+
|
|
134
|
+
Raises:
|
|
135
|
+
TrismikApiError: If API request fails.
|
|
136
|
+
"""
|
|
137
|
+
try:
|
|
138
|
+
url = "/client/sessions"
|
|
139
|
+
headers = {"Authorization": f"Bearer {token}"}
|
|
140
|
+
body = {"testId": test_id}
|
|
141
|
+
response = await self._http_client.post(url, headers=headers,
|
|
142
|
+
json=body)
|
|
143
|
+
response.raise_for_status()
|
|
144
|
+
json = response.json()
|
|
145
|
+
return TrismikResponseMapper.to_session(json)
|
|
146
|
+
except httpx.HTTPStatusError as e:
|
|
147
|
+
raise TrismikApiError(
|
|
148
|
+
TrismikUtils.get_error_message(e.response)) from e
|
|
149
|
+
except httpx.HTTPError as e:
|
|
150
|
+
raise TrismikApiError(str(e)) from e
|
|
151
|
+
|
|
152
|
+
async def current_item(
|
|
153
|
+
self,
|
|
154
|
+
session_url: str,
|
|
155
|
+
token: str
|
|
156
|
+
) -> TrismikItem:
|
|
157
|
+
"""
|
|
158
|
+
Retrieves the current test item.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
session_url (str): URL of the session.
|
|
162
|
+
token (str): Authentication token.
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
TrismikItem: Current test item.
|
|
166
|
+
|
|
167
|
+
Raises:
|
|
168
|
+
TrismikApiError: If API request fails.
|
|
169
|
+
"""
|
|
170
|
+
try:
|
|
171
|
+
url = f"{session_url}/item"
|
|
172
|
+
headers = {"Authorization": f"Bearer {token}"}
|
|
173
|
+
response = await self._http_client.get(url, headers=headers)
|
|
174
|
+
response.raise_for_status()
|
|
175
|
+
json = response.json()
|
|
176
|
+
return TrismikResponseMapper.to_item(json)
|
|
177
|
+
except httpx.HTTPStatusError as e:
|
|
178
|
+
raise TrismikApiError(
|
|
179
|
+
TrismikUtils.get_error_message(e.response)) from e
|
|
180
|
+
except httpx.HTTPError as e:
|
|
181
|
+
raise TrismikApiError(str(e)) from e
|
|
182
|
+
|
|
183
|
+
async def respond_to_current_item(
|
|
184
|
+
self,
|
|
185
|
+
session_url: str,
|
|
186
|
+
value: Any,
|
|
187
|
+
token: str
|
|
188
|
+
) -> TrismikItem | None:
|
|
189
|
+
"""
|
|
190
|
+
Responds to the current test item.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
session_url (str): URL of the session.
|
|
194
|
+
value (Any): Response value.
|
|
195
|
+
token (str): Authentication token.
|
|
196
|
+
|
|
197
|
+
Returns:
|
|
198
|
+
TrismikItem | None: Next test item or None if session is finished.
|
|
199
|
+
|
|
200
|
+
Raises:
|
|
201
|
+
TrismikApiError: If API request fails.
|
|
202
|
+
"""
|
|
203
|
+
try:
|
|
204
|
+
url = f"{session_url}/item"
|
|
205
|
+
body = {"value": value}
|
|
206
|
+
headers = {"Authorization": f"Bearer {token}"}
|
|
207
|
+
response = await self._http_client.post(
|
|
208
|
+
url, headers=headers, json=body
|
|
209
|
+
)
|
|
210
|
+
response.raise_for_status()
|
|
211
|
+
if response.status_code == 204:
|
|
212
|
+
return None
|
|
213
|
+
else:
|
|
214
|
+
json = response.json()
|
|
215
|
+
return TrismikResponseMapper.to_item(json)
|
|
216
|
+
except httpx.HTTPStatusError as e:
|
|
217
|
+
raise TrismikApiError(
|
|
218
|
+
TrismikUtils.get_error_message(e.response)) from e
|
|
219
|
+
except httpx.HTTPError as e:
|
|
220
|
+
raise TrismikApiError(str(e)) from e
|
|
221
|
+
|
|
222
|
+
async def results(self,
|
|
223
|
+
session_url: str,
|
|
224
|
+
token: str
|
|
225
|
+
) -> List[TrismikResult]:
|
|
226
|
+
"""
|
|
227
|
+
Retrieves the results of a session.
|
|
228
|
+
|
|
229
|
+
Args:
|
|
230
|
+
session_url (str): URL of the session.
|
|
231
|
+
token (str): Authentication token.
|
|
232
|
+
|
|
233
|
+
Returns:
|
|
234
|
+
List[TrismikResult]: Results of the session.
|
|
235
|
+
|
|
236
|
+
Raises:
|
|
237
|
+
TrismikApiError: If API request fails.
|
|
238
|
+
"""
|
|
239
|
+
try:
|
|
240
|
+
url = f"{session_url}/results"
|
|
241
|
+
headers = {"Authorization": f"Bearer {token}"}
|
|
242
|
+
response = await self._http_client.get(url, headers=headers)
|
|
243
|
+
response.raise_for_status()
|
|
244
|
+
json = response.json()
|
|
245
|
+
return TrismikResponseMapper.to_results(json)
|
|
246
|
+
except httpx.HTTPStatusError as e:
|
|
247
|
+
raise TrismikApiError(
|
|
248
|
+
TrismikUtils.get_error_message(e.response)) from e
|
|
249
|
+
except httpx.HTTPError as e:
|
|
250
|
+
raise TrismikApiError(str(e)) from e
|
|
251
|
+
|
|
252
|
+
async def responses(self,
|
|
253
|
+
session_url: str,
|
|
254
|
+
token: str
|
|
255
|
+
) -> List[TrismikResponse]:
|
|
256
|
+
"""
|
|
257
|
+
Retrieves responses to session items.
|
|
258
|
+
|
|
259
|
+
Args:
|
|
260
|
+
session_url (str): URL of the session.
|
|
261
|
+
token (str): Authentication token.
|
|
262
|
+
|
|
263
|
+
Returns:
|
|
264
|
+
List[TrismikResponse]: Responses of the session.
|
|
265
|
+
|
|
266
|
+
Raises:
|
|
267
|
+
TrismikApiError: If API request fails.
|
|
268
|
+
"""
|
|
269
|
+
try:
|
|
270
|
+
url = f"{session_url}/responses"
|
|
271
|
+
headers = {"Authorization": f"Bearer {token}"}
|
|
272
|
+
response = await self._http_client.get(url, headers=headers)
|
|
273
|
+
response.raise_for_status()
|
|
274
|
+
json = response.json()
|
|
275
|
+
return TrismikResponseMapper.to_responses(json)
|
|
276
|
+
except httpx.HTTPStatusError as e:
|
|
277
|
+
raise TrismikApiError(
|
|
278
|
+
TrismikUtils.get_error_message(e.response)) from e
|
|
279
|
+
except httpx.HTTPError as e:
|
|
280
|
+
raise TrismikApiError(str(e)) from e
|
trismik/exceptions.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
class TrismikError(Exception):
|
|
2
|
+
"""
|
|
3
|
+
Base class for all exceptions raised.
|
|
4
|
+
Raised when an error occurs in the Trismik package, i.e. configuration.
|
|
5
|
+
"""
|
|
6
|
+
pass
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TrismikApiError(TrismikError):
|
|
10
|
+
"""
|
|
11
|
+
Raised when an error occurs while interacting with the Trismik API
|
|
12
|
+
"""
|
|
13
|
+
pass
|
trismik/runner.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from datetime import datetime, timedelta
|
|
2
|
+
from typing import List, Callable, Any, Optional
|
|
3
|
+
|
|
4
|
+
from .client import TrismikClient
|
|
5
|
+
from .types import (
|
|
6
|
+
TrismikAuth,
|
|
7
|
+
TrismikItem,
|
|
8
|
+
TrismikResult,
|
|
9
|
+
TrismikResultsAndResponses,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TrismikRunner:
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
item_processor: Callable[[TrismikItem], Any],
|
|
17
|
+
client: Optional[TrismikClient] = None,
|
|
18
|
+
auth: Optional[TrismikAuth] = None,
|
|
19
|
+
) -> None:
|
|
20
|
+
"""
|
|
21
|
+
Initializes a new Trismik runner.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
item_processor (Callable[[TrismikItem], Any]): Function to process test items.
|
|
25
|
+
client (Optional[TrismikClient]): Trismik client to use for requests.
|
|
26
|
+
auth (Optional[TrismikAuth]): Authentication token to use for requests
|
|
27
|
+
|
|
28
|
+
Raises:
|
|
29
|
+
TrismikApiError: If API request fails.
|
|
30
|
+
"""
|
|
31
|
+
self._item_processor = item_processor
|
|
32
|
+
self._client = client
|
|
33
|
+
self._auth = auth
|
|
34
|
+
|
|
35
|
+
def run(self,
|
|
36
|
+
test_id: str,
|
|
37
|
+
with_responses: bool = False,
|
|
38
|
+
) -> List[TrismikResult] | TrismikResultsAndResponses:
|
|
39
|
+
"""
|
|
40
|
+
Runs a test.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
test_id (str): ID of the test to run.
|
|
44
|
+
with_responses (bool): If True, responses will be included with the results.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
List[TrismikResult] | TrismikResultsAndResponses: Either just test results, or with responses.
|
|
48
|
+
|
|
49
|
+
Raises:
|
|
50
|
+
TrismikApiError: If API request fails.
|
|
51
|
+
"""
|
|
52
|
+
self._init()
|
|
53
|
+
self._refresh_token_if_needed()
|
|
54
|
+
session = self._client.create_session(test_id, self._auth.token)
|
|
55
|
+
self._run_session(session.url)
|
|
56
|
+
results = self._client.results(session.url, self._auth.token)
|
|
57
|
+
|
|
58
|
+
if with_responses:
|
|
59
|
+
responses = self._client.responses(session.url, self._auth.token)
|
|
60
|
+
return TrismikResultsAndResponses(results, responses)
|
|
61
|
+
else:
|
|
62
|
+
return results
|
|
63
|
+
|
|
64
|
+
def _run_session(self, session_url: str) -> None:
|
|
65
|
+
item = self._client.current_item(session_url, self._auth.token)
|
|
66
|
+
while item is not None:
|
|
67
|
+
self._refresh_token_if_needed()
|
|
68
|
+
response = self._item_processor(item)
|
|
69
|
+
item = self._client.respond_to_current_item(
|
|
70
|
+
session_url, response, self._auth.token
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
def _init(self) -> None:
|
|
74
|
+
if self._client is None:
|
|
75
|
+
self._client = TrismikClient()
|
|
76
|
+
|
|
77
|
+
if self._auth is None:
|
|
78
|
+
self._auth = self._client.authenticate()
|
|
79
|
+
|
|
80
|
+
def _refresh_token_if_needed(self) -> None:
|
|
81
|
+
if self._token_needs_refresh():
|
|
82
|
+
self._auth = self._client.refresh_token(self._auth.token)
|
|
83
|
+
|
|
84
|
+
def _token_needs_refresh(self) -> bool:
|
|
85
|
+
return self._auth.expires < (datetime.now() + timedelta(minutes=5))
|
trismik/runner_async.py
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
from datetime import datetime, timedelta
|
|
2
|
+
from typing import List, Callable, Any, Awaitable, Optional
|
|
3
|
+
|
|
4
|
+
from .client_async import TrismikAsyncClient
|
|
5
|
+
from .types import (
|
|
6
|
+
TrismikAuth,
|
|
7
|
+
TrismikItem,
|
|
8
|
+
TrismikResult,
|
|
9
|
+
TrismikResultsAndResponses,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TrismikAsyncRunner:
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
item_processor: Callable[[TrismikItem], Awaitable[Any]],
|
|
17
|
+
client: Optional[TrismikAsyncClient] = None,
|
|
18
|
+
auth: Optional[TrismikAuth] = None,
|
|
19
|
+
) -> None:
|
|
20
|
+
"""
|
|
21
|
+
Initializes a new Trismik runner (async version).
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
item_processor (Callable[[TrismikItem], Any]): Function to process test items.
|
|
25
|
+
client (Optional[TrismikClient]): Trismik client to use for requests.
|
|
26
|
+
auth (Optional[TrismikAuth]): Authentication token to use for requests
|
|
27
|
+
|
|
28
|
+
Raises:
|
|
29
|
+
TrismikApiError: If API request fails.
|
|
30
|
+
"""
|
|
31
|
+
self._item_processor = item_processor
|
|
32
|
+
self._client = client
|
|
33
|
+
self._auth = auth
|
|
34
|
+
|
|
35
|
+
async def run(self,
|
|
36
|
+
test_id: str,
|
|
37
|
+
with_responses: bool = False,
|
|
38
|
+
) -> List[TrismikResult] | TrismikResultsAndResponses:
|
|
39
|
+
"""
|
|
40
|
+
Runs a test.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
test_id (str): ID of the test to run.
|
|
44
|
+
with_responses (bool): If True, responses will be included with the results.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
List[TrismikResult] | TrismikResultsAndResponses: Either just test results, or with responses.
|
|
48
|
+
|
|
49
|
+
Raises:
|
|
50
|
+
TrismikApiError: If API request fails.
|
|
51
|
+
"""
|
|
52
|
+
await self._init()
|
|
53
|
+
await self._refresh_token_if_needed()
|
|
54
|
+
session = await self._client.create_session(test_id, self._auth.token)
|
|
55
|
+
await self._run_session(session.url)
|
|
56
|
+
results = await self._client.results(session.url, self._auth.token)
|
|
57
|
+
|
|
58
|
+
if with_responses:
|
|
59
|
+
responses = await self._client.responses(session.url,
|
|
60
|
+
self._auth.token)
|
|
61
|
+
return TrismikResultsAndResponses(results, responses)
|
|
62
|
+
else:
|
|
63
|
+
return results
|
|
64
|
+
|
|
65
|
+
async def _run_session(self, session_url: str) -> None:
|
|
66
|
+
await self._init()
|
|
67
|
+
await self._refresh_token_if_needed()
|
|
68
|
+
item = await self._client.current_item(session_url, self._auth.token)
|
|
69
|
+
while item is not None:
|
|
70
|
+
await self._refresh_token_if_needed()
|
|
71
|
+
response = await self._item_processor(item)
|
|
72
|
+
item = await self._client.respond_to_current_item(
|
|
73
|
+
session_url, response, self._auth.token)
|
|
74
|
+
|
|
75
|
+
async def _init(self) -> None:
|
|
76
|
+
if self._client is None:
|
|
77
|
+
self._client = TrismikAsyncClient()
|
|
78
|
+
|
|
79
|
+
if self._auth is None:
|
|
80
|
+
self._auth = await self._client.authenticate()
|
|
81
|
+
|
|
82
|
+
async def _refresh_token_if_needed(self) -> None:
|
|
83
|
+
if self._token_needs_refresh():
|
|
84
|
+
self._auth = await self._client.refresh_token(self._auth.token)
|
|
85
|
+
|
|
86
|
+
def _token_needs_refresh(self) -> bool:
|
|
87
|
+
return self._auth.expires < (datetime.now() + timedelta(minutes=5))
|
trismik/types.py
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import List, Any
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass
|
|
7
|
+
class TrismikAuth:
|
|
8
|
+
"""
|
|
9
|
+
Authentication token.
|
|
10
|
+
|
|
11
|
+
Attributes:
|
|
12
|
+
token (str): Authentication token value.
|
|
13
|
+
expires (datetime): Expiration date.
|
|
14
|
+
"""
|
|
15
|
+
token: str
|
|
16
|
+
expires: datetime
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class TrismikTest:
|
|
21
|
+
"""
|
|
22
|
+
Available test.
|
|
23
|
+
|
|
24
|
+
Attributes:
|
|
25
|
+
id (str): Test ID.
|
|
26
|
+
name (str): Test name.
|
|
27
|
+
"""
|
|
28
|
+
id: str
|
|
29
|
+
name: str
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class TrismikSession:
|
|
34
|
+
"""
|
|
35
|
+
Test session.
|
|
36
|
+
|
|
37
|
+
Attributes:
|
|
38
|
+
id (str): Session ID.
|
|
39
|
+
url (str): Session URL.
|
|
40
|
+
status (str): Session status
|
|
41
|
+
"""
|
|
42
|
+
id: str
|
|
43
|
+
url: str
|
|
44
|
+
status: str
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@dataclass
|
|
48
|
+
class TrismikItem:
|
|
49
|
+
"""
|
|
50
|
+
Base class for test items.
|
|
51
|
+
|
|
52
|
+
Attributes:
|
|
53
|
+
id (str): Item ID.
|
|
54
|
+
"""
|
|
55
|
+
id: str
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclass
|
|
59
|
+
class TrismikChoice:
|
|
60
|
+
"""
|
|
61
|
+
Base class for choices in items that use them.
|
|
62
|
+
|
|
63
|
+
Attributes:
|
|
64
|
+
id (str): Choice ID.
|
|
65
|
+
"""
|
|
66
|
+
id: str
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@dataclass
|
|
70
|
+
class TrismikTextChoice(TrismikChoice):
|
|
71
|
+
"""
|
|
72
|
+
Text choice.
|
|
73
|
+
|
|
74
|
+
Attributes:
|
|
75
|
+
text (str): Choice text.
|
|
76
|
+
"""
|
|
77
|
+
text: str
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@dataclass
|
|
81
|
+
class TrismikMultipleChoiceTextItem(TrismikItem):
|
|
82
|
+
"""
|
|
83
|
+
Multiple choice text item.
|
|
84
|
+
|
|
85
|
+
Attributes:
|
|
86
|
+
question (str): Question text.
|
|
87
|
+
choices (List[TrismikTextChoice]): List of choices.
|
|
88
|
+
"""
|
|
89
|
+
question: str
|
|
90
|
+
choices: List[TrismikTextChoice]
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@dataclass
|
|
94
|
+
class TrismikResult:
|
|
95
|
+
"""
|
|
96
|
+
Test result.
|
|
97
|
+
|
|
98
|
+
Attributes:
|
|
99
|
+
trait (str): Trait name.
|
|
100
|
+
name (str): Result name/type.
|
|
101
|
+
value (Any): Result value.
|
|
102
|
+
"""
|
|
103
|
+
trait: str
|
|
104
|
+
name: str
|
|
105
|
+
value: Any
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@dataclass
|
|
109
|
+
class TrismikResponse:
|
|
110
|
+
"""
|
|
111
|
+
Test result.
|
|
112
|
+
|
|
113
|
+
Attributes:
|
|
114
|
+
item_id (str): Item ID.
|
|
115
|
+
value (Any): Result value.
|
|
116
|
+
score (float): Score.
|
|
117
|
+
"""
|
|
118
|
+
item_id: str
|
|
119
|
+
value: Any
|
|
120
|
+
score: float
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@dataclass
|
|
124
|
+
class TrismikResultsAndResponses:
|
|
125
|
+
"""
|
|
126
|
+
Test results and responses.
|
|
127
|
+
|
|
128
|
+
Attributes:
|
|
129
|
+
results (List[TrismikResult]): Results.
|
|
130
|
+
responses (List[TrismikResponse]): Responses.
|
|
131
|
+
"""
|
|
132
|
+
results: List[TrismikResult]
|
|
133
|
+
responses: List[TrismikResponse]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Cambridge Enterprise
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: trismik
|
|
3
|
+
Version: 0.9.0
|
|
4
|
+
Summary:
|
|
5
|
+
Author: Bartosz Kielczewski
|
|
6
|
+
Author-email: bk352@cam.ac.uk
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Requires-Dist: httpx (>=0.27.2,<0.28.0)
|
|
15
|
+
Requires-Dist: python-dateutil (>=2.9.0.post0,<3.0.0)
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
Trismik Python SDK
|
|
19
|
+
==================
|
|
20
|
+
|
|
21
|
+
This is the official Python SDK for Trismik. It provides a simple way to interact with the Trismik
|
|
22
|
+
API.
|
|
23
|
+
|
|
24
|
+
Usage
|
|
25
|
+
-----
|
|
26
|
+
|
|
27
|
+
1. ```pip install trismik```
|
|
28
|
+
2. Set the following environment variable. Alternatively, put it into `.env` file
|
|
29
|
+
in the root of your project, and load them using `python-dotenv` package:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
TRISMIK_API_KEY=<api_key>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
3. Refer to examples:
|
|
36
|
+
* [example_runner.py](./examples/example_runner.py) - run test using high-level `TrismikRunner`
|
|
37
|
+
class
|
|
38
|
+
* [example_runner_async.py](./examples/example_runner_async.py) - like above, but with async
|
|
39
|
+
support
|
|
40
|
+
* [example_client.py](./examples/example_client.py) - run test using `TrismikClient` directly
|
|
41
|
+
* [example_client_async.py](./examples/example_client_async.py) - like above, but with async
|
|
42
|
+
support
|
|
43
|
+
|
|
44
|
+
Contributing
|
|
45
|
+
------------
|
|
46
|
+
|
|
47
|
+
1. Install [Python Poetry](https://python-poetry.org/docs/#installing-with-the-official-installer)
|
|
48
|
+
2. ```git clone https://github.com/trismik/trismik-python.git```, or if cloned previously:
|
|
49
|
+
```git pull``` to update
|
|
50
|
+
3. ```cd ./trismik-python```
|
|
51
|
+
4. ```poetry install```
|
|
52
|
+
5. ```poetry run pytest```
|
|
53
|
+
|
|
54
|
+
Publishing to TestPyPi
|
|
55
|
+
----------------------
|
|
56
|
+
|
|
57
|
+
1. ```poetry config repositories.testpypi https://test.pypi.org/legacy/```
|
|
58
|
+
2. ```poetry config pypi-token.testpypi <token>```
|
|
59
|
+
3. ```poetry publish --build --repository testpypi```
|
|
60
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
trismik/__init__.py,sha256=DoKoJyAtB8C8La-Jjn8PS7uqIpGutWxeI48dIjhywPY,487
|
|
2
|
+
trismik/_mapper.py,sha256=HX4pQw3pZKsiOwuIebLbDP9_aTO8E9tlsSjUhU9dQTQ,2359
|
|
3
|
+
trismik/_utils.py,sha256=5_zRwgfF7flfU0shQm2BzT5A-coIV7MWeq_MoRmsoQc,1195
|
|
4
|
+
trismik/client.py,sha256=nsYdMHtELlBiwzfh-ameSwlPd-4-vQPg9eP-gYxu5gA,9318
|
|
5
|
+
trismik/client_async.py,sha256=vAByw1ZvxtrzQx-IQ9K-k71RimvceH6POiSJpSPZKB4,9564
|
|
6
|
+
trismik/exceptions.py,sha256=QcAH95FeZNXl4eDTCvqq3OhHrK976de1wd7bNEIfa88,322
|
|
7
|
+
trismik/runner.py,sha256=VwkNKVA9On8zqEclALR_ffkSSiyNfYHCmtgGm1ASMl4,2906
|
|
8
|
+
trismik/runner_async.py,sha256=sXHyMrUHmJ5bsDUz3KpTIPEFQpWSTj0YpqRv8Qs9FuE,3181
|
|
9
|
+
trismik/types.py,sha256=1oDZ5pIoDr8WvY0LquChiPbcdqMvFt4CfS5rZAR66EM,2318
|
|
10
|
+
trismik-0.9.0.dist-info/LICENSE,sha256=EbaNeGU9EYIF6mQ0iI3nnJ9UwEMghRj8sRNdjNTq96g,1098
|
|
11
|
+
trismik-0.9.0.dist-info/METADATA,sha256=32QHAFdQx8L3IG3PNjoojYtwJpINrlITkBKguhZDVFE,1970
|
|
12
|
+
trismik-0.9.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
13
|
+
trismik-0.9.0.dist-info/RECORD,,
|