trismik 0.9.0__tar.gz → 0.9.1__tar.gz

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,21 +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.
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.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: trismik
3
- Version: 0.9.0
3
+ Version: 0.9.1
4
4
  Summary:
5
5
  Author: Bartosz Kielczewski
6
6
  Author-email: bk352@cam.ac.uk
@@ -11,6 +11,7 @@ Classifier: Programming Language :: Python :: 3.9
11
11
  Classifier: Programming Language :: Python :: 3.10
12
12
  Classifier: Programming Language :: Python :: 3.11
13
13
  Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
14
15
  Requires-Dist: httpx (>=0.27.2,<0.28.0)
15
16
  Requires-Dist: python-dateutil (>=2.9.0.post0,<3.0.0)
16
17
  Description-Content-Type: text/markdown
@@ -51,10 +52,3 @@ Contributing
51
52
  4. ```poetry install```
52
53
  5. ```poetry run pytest```
53
54
 
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
-
@@ -1,42 +1,35 @@
1
- Trismik Python SDK
2
- ==================
3
-
4
- This is the official Python SDK for Trismik. It provides a simple way to interact with the Trismik
5
- API.
6
-
7
- Usage
8
- -----
9
-
10
- 1. ```pip install trismik```
11
- 2. Set the following environment variable. Alternatively, put it into `.env` file
12
- in the root of your project, and load them using `python-dotenv` package:
13
-
14
- ```
15
- TRISMIK_API_KEY=<api_key>
16
- ```
17
-
18
- 3. Refer to examples:
19
- * [example_runner.py](./examples/example_runner.py) - run test using high-level `TrismikRunner`
20
- class
21
- * [example_runner_async.py](./examples/example_runner_async.py) - like above, but with async
22
- support
23
- * [example_client.py](./examples/example_client.py) - run test using `TrismikClient` directly
24
- * [example_client_async.py](./examples/example_client_async.py) - like above, but with async
25
- support
26
-
27
- Contributing
28
- ------------
29
-
30
- 1. Install [Python Poetry](https://python-poetry.org/docs/#installing-with-the-official-installer)
31
- 2. ```git clone https://github.com/trismik/trismik-python.git```, or if cloned previously:
32
- ```git pull``` to update
33
- 3. ```cd ./trismik-python```
34
- 4. ```poetry install```
35
- 5. ```poetry run pytest```
36
-
37
- Publishing to TestPyPi
38
- ----------------------
39
-
40
- 1. ```poetry config repositories.testpypi https://test.pypi.org/legacy/```
41
- 2. ```poetry config pypi-token.testpypi <token>```
42
- 3. ```poetry publish --build --repository testpypi```
1
+ Trismik Python SDK
2
+ ==================
3
+
4
+ This is the official Python SDK for Trismik. It provides a simple way to interact with the Trismik
5
+ API.
6
+
7
+ Usage
8
+ -----
9
+
10
+ 1. ```pip install trismik```
11
+ 2. Set the following environment variable. Alternatively, put it into `.env` file
12
+ in the root of your project, and load them using `python-dotenv` package:
13
+
14
+ ```
15
+ TRISMIK_API_KEY=<api_key>
16
+ ```
17
+
18
+ 3. Refer to examples:
19
+ * [example_runner.py](./examples/example_runner.py) - run test using high-level `TrismikRunner`
20
+ class
21
+ * [example_runner_async.py](./examples/example_runner_async.py) - like above, but with async
22
+ support
23
+ * [example_client.py](./examples/example_client.py) - run test using `TrismikClient` directly
24
+ * [example_client_async.py](./examples/example_client_async.py) - like above, but with async
25
+ support
26
+
27
+ Contributing
28
+ ------------
29
+
30
+ 1. Install [Python Poetry](https://python-poetry.org/docs/#installing-with-the-official-installer)
31
+ 2. ```git clone https://github.com/trismik/trismik-python.git```, or if cloned previously:
32
+ ```git pull``` to update
33
+ 3. ```cd ./trismik-python```
34
+ 4. ```poetry install```
35
+ 5. ```poetry run pytest```
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "trismik"
3
- version = "0.9.0"
3
+ version = "0.9.1"
4
4
  description = ""
5
5
  authors = ["Bartosz Kielczewski <bk352@cam.ac.uk>"]
6
6
  readme = "README.md"
@@ -1,20 +1,21 @@
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
- )
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
+ TrismikRunResults,
20
+ TrismikSessionMetadata,
21
+ )
@@ -1,79 +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
- ]
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
+ ]
@@ -1,44 +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
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
@@ -12,6 +12,7 @@ from .types import (
12
12
  TrismikItem,
13
13
  TrismikResult,
14
14
  TrismikResponse,
15
+ TrismikSessionMetadata
15
16
  )
16
17
 
17
18
 
@@ -120,7 +121,7 @@ class TrismikClient:
120
121
  except httpx.HTTPError as e:
121
122
  raise TrismikApiError(str(e)) from e
122
123
 
123
- def create_session(self, test_id: str, token: str) -> TrismikSession:
124
+ def create_session(self, test_id: str, metadata: TrismikSessionMetadata, token: str) -> TrismikSession:
124
125
  """
125
126
  Creates a new session for a test.
126
127
 
@@ -137,7 +138,7 @@ class TrismikClient:
137
138
  try:
138
139
  url = "/client/sessions"
139
140
  headers = {"Authorization": f"Bearer {token}"}
140
- body = {"testId": test_id, }
141
+ body = {"testId": test_id, "metadata": metadata.toDict() }
141
142
  response = self._http_client.post(url, headers=headers, json=body)
142
143
  response.raise_for_status()
143
144
  json = response.json()
@@ -147,6 +148,61 @@ class TrismikClient:
147
148
  TrismikUtils.get_error_message(e.response)) from e
148
149
  except httpx.HTTPError as e:
149
150
  raise TrismikApiError(str(e)) from e
151
+
152
+ def create_replay_session(self, previous_session_id: str, metadata: TrismikSessionMetadata, token: str) -> TrismikSession:
153
+ """
154
+ Creates a new session that replays exactly the question sequence of a previous session
155
+
156
+ Args:
157
+ previous_session_id (str): Session id of the session to replay.
158
+ token (str): Authentication token.
159
+
160
+ Returns:
161
+ TrismikSession: New session
162
+
163
+ Raises:
164
+ TrismikApiError: If API request fails.
165
+ """
166
+ try:
167
+ url = "/client/sessions/replay"
168
+ headers = {"Authorization": f"Bearer {token}"}
169
+ body = {"previousSessionToken": previous_session_id, "metadata": metadata.toDict(), }
170
+ response = self._http_client.post(url, headers=headers, json=body)
171
+ response.raise_for_status()
172
+ json = response.json()
173
+ return TrismikResponseMapper.to_session(json)
174
+ except httpx.HTTPStatusError as e:
175
+ raise TrismikApiError(
176
+ TrismikUtils.get_error_message(e.response)) from e
177
+ except httpx.HTTPError as e:
178
+ raise TrismikApiError(str(e)) from e
179
+
180
+ def add_metadata(self, session_id: str, metadata: TrismikSessionMetadata, token: str) -> None:
181
+ """
182
+ Adds metadata to the session, merging it with any already stored
183
+
184
+ Args:
185
+ session_id (str): id of the session object
186
+ metadata: object cotaining the metadata to add
187
+ token (str): Authentication token.
188
+
189
+ Returns:
190
+ None
191
+
192
+ Raises:
193
+ TrismikApiError: If API request fails.
194
+ """
195
+ try:
196
+ url = f"/client/sessions/{session_id}/metadata"
197
+ headers = {"Authorization": f"Bearer {token}"}
198
+ body = metadata.toDict()
199
+ response = self._http_client.post(url, headers=headers, json=body)
200
+ response.raise_for_status()
201
+ except httpx.HTTPStatusError as e:
202
+ raise TrismikApiError(
203
+ TrismikUtils.get_error_message(e.response)) from e
204
+ except httpx.HTTPError as e:
205
+ raise TrismikApiError(str(e)) from e
150
206
 
151
207
  def current_item(
152
208
  self,