trismik 0.9.0__py3-none-any.whl → 0.9.1__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 +21 -20
- trismik/_mapper.py +79 -79
- trismik/_utils.py +44 -44
- trismik/client.py +58 -2
- trismik/client_async.py +338 -280
- trismik/runner.py +119 -85
- trismik/runner_async.py +121 -87
- trismik/types.py +163 -133
- {trismik-0.9.0.dist-info → trismik-0.9.1.dist-info}/LICENSE +21 -21
- {trismik-0.9.0.dist-info → trismik-0.9.1.dist-info}/METADATA +3 -9
- trismik-0.9.1.dist-info/RECORD +13 -0
- {trismik-0.9.0.dist-info → trismik-0.9.1.dist-info}/WHEEL +1 -1
- trismik-0.9.0.dist-info/RECORD +0 -13
trismik/runner.py
CHANGED
|
@@ -1,85 +1,119 @@
|
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
self.
|
|
33
|
-
self.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
self.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
+
TrismikRunResults,
|
|
10
|
+
TrismikSessionMetadata,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TrismikRunner:
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
item_processor: Callable[[TrismikItem], Any],
|
|
18
|
+
client: Optional[TrismikClient] = None,
|
|
19
|
+
auth: Optional[TrismikAuth] = None,
|
|
20
|
+
) -> None:
|
|
21
|
+
"""
|
|
22
|
+
Initializes a new Trismik runner.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
item_processor (Callable[[TrismikItem], Any]): Function to process test items.
|
|
26
|
+
client (Optional[TrismikClient]): Trismik client to use for requests.
|
|
27
|
+
auth (Optional[TrismikAuth]): Authentication token to use for requests
|
|
28
|
+
|
|
29
|
+
Raises:
|
|
30
|
+
TrismikApiError: If API request fails.
|
|
31
|
+
"""
|
|
32
|
+
self._item_processor = item_processor
|
|
33
|
+
self._client = client
|
|
34
|
+
self._auth = auth
|
|
35
|
+
|
|
36
|
+
def run(self,
|
|
37
|
+
test_id: str,
|
|
38
|
+
session_metadata: TrismikSessionMetadata,
|
|
39
|
+
with_responses: bool = False,
|
|
40
|
+
) -> TrismikRunResults:
|
|
41
|
+
"""
|
|
42
|
+
Runs a test.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
test_id (str): ID of the test to run.
|
|
46
|
+
with_responses (bool): If True, responses will be included with the results.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
TrismikRunResults: Either just test results, or with responses.
|
|
50
|
+
|
|
51
|
+
Raises:
|
|
52
|
+
TrismikApiError: If API request fails.
|
|
53
|
+
"""
|
|
54
|
+
self._init()
|
|
55
|
+
self._refresh_token_if_needed()
|
|
56
|
+
session = self._client.create_session(test_id, session_metadata, self._auth.token)
|
|
57
|
+
|
|
58
|
+
self._run_session(session.url)
|
|
59
|
+
results = self._client.results(session.url, self._auth.token)
|
|
60
|
+
|
|
61
|
+
if with_responses:
|
|
62
|
+
responses = self._client.responses(session.url, self._auth.token)
|
|
63
|
+
return TrismikRunResults(session.id, results, responses)
|
|
64
|
+
else:
|
|
65
|
+
return TrismikRunResults(session.id, results)
|
|
66
|
+
|
|
67
|
+
def _run_session(self, session_url: str) -> None:
|
|
68
|
+
item = self._client.current_item(session_url, self._auth.token)
|
|
69
|
+
while item is not None:
|
|
70
|
+
self._refresh_token_if_needed()
|
|
71
|
+
response = self._item_processor(item)
|
|
72
|
+
item = self._client.respond_to_current_item(
|
|
73
|
+
session_url, response, self._auth.token
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
def run_replay(self,
|
|
77
|
+
previous_session_id: str,
|
|
78
|
+
session_metadata: TrismikSessionMetadata,
|
|
79
|
+
with_responses: bool = False,
|
|
80
|
+
) -> TrismikRunResults:
|
|
81
|
+
"""
|
|
82
|
+
Replay the exact sequence of questions from a previous session
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
previous_session_id (str): ID of a previous session to replay
|
|
86
|
+
with_responses (bool): If True, responses will be included with the results.
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
TrismikRunResults: Either just test results, or with responses.
|
|
90
|
+
|
|
91
|
+
Raises:
|
|
92
|
+
TrismikApiError: If API request fails.
|
|
93
|
+
"""
|
|
94
|
+
self._init()
|
|
95
|
+
self._refresh_token_if_needed()
|
|
96
|
+
session = self._client.create_replay_session(previous_session_id, session_metadata, self._auth.token)
|
|
97
|
+
|
|
98
|
+
self._run_session(session.url)
|
|
99
|
+
results = self._client.results(session.url, self._auth.token)
|
|
100
|
+
|
|
101
|
+
if with_responses:
|
|
102
|
+
responses = self._client.responses(session.url, self._auth.token)
|
|
103
|
+
return TrismikRunResults(session.id, results, responses)
|
|
104
|
+
else:
|
|
105
|
+
return TrismikRunResults(session.id, results)
|
|
106
|
+
|
|
107
|
+
def _init(self) -> None:
|
|
108
|
+
if self._client is None:
|
|
109
|
+
self._client = TrismikClient()
|
|
110
|
+
|
|
111
|
+
if self._auth is None:
|
|
112
|
+
self._auth = self._client.authenticate()
|
|
113
|
+
|
|
114
|
+
def _refresh_token_if_needed(self) -> None:
|
|
115
|
+
if self._token_needs_refresh():
|
|
116
|
+
self._auth = self._client.refresh_token(self._auth.token)
|
|
117
|
+
|
|
118
|
+
def _token_needs_refresh(self) -> bool:
|
|
119
|
+
return self._auth.expires < (datetime.now() + timedelta(minutes=5))
|
trismik/runner_async.py
CHANGED
|
@@ -1,87 +1,121 @@
|
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
self.
|
|
33
|
-
self.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
await self.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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
|
+
TrismikRunResults,
|
|
10
|
+
TrismikSessionMetadata,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TrismikAsyncRunner:
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
item_processor: Callable[[TrismikItem], Awaitable[Any]],
|
|
18
|
+
client: Optional[TrismikAsyncClient] = None,
|
|
19
|
+
auth: Optional[TrismikAuth] = None,
|
|
20
|
+
) -> None:
|
|
21
|
+
"""
|
|
22
|
+
Initializes a new Trismik runner (async version).
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
item_processor (Callable[[TrismikItem], Any]): Function to process test items.
|
|
26
|
+
client (Optional[TrismikClient]): Trismik client to use for requests.
|
|
27
|
+
auth (Optional[TrismikAuth]): Authentication token to use for requests
|
|
28
|
+
|
|
29
|
+
Raises:
|
|
30
|
+
TrismikApiError: If API request fails.
|
|
31
|
+
"""
|
|
32
|
+
self._item_processor = item_processor
|
|
33
|
+
self._client = client
|
|
34
|
+
self._auth = auth
|
|
35
|
+
|
|
36
|
+
async def run(self,
|
|
37
|
+
test_id: str,
|
|
38
|
+
session_metadata: TrismikSessionMetadata,
|
|
39
|
+
with_responses: bool = False,
|
|
40
|
+
) -> TrismikRunResults:
|
|
41
|
+
"""
|
|
42
|
+
Runs a test.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
test_id (str): ID of the test to run.
|
|
46
|
+
with_responses (bool): If True, responses will be included with the results.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
TrismikRunResults: Either just test results, or with responses.
|
|
50
|
+
|
|
51
|
+
Raises:
|
|
52
|
+
TrismikApiError: If API request fails.
|
|
53
|
+
"""
|
|
54
|
+
await self._init()
|
|
55
|
+
await self._refresh_token_if_needed()
|
|
56
|
+
session = await self._client.create_session(test_id, session_metadata, self._auth.token)
|
|
57
|
+
|
|
58
|
+
await self._run_session(session.url)
|
|
59
|
+
results = await self._client.results(session.url, self._auth.token)
|
|
60
|
+
|
|
61
|
+
if with_responses:
|
|
62
|
+
responses = await self._client.responses(session.url,
|
|
63
|
+
self._auth.token)
|
|
64
|
+
return TrismikRunResults(session.id, results, responses)
|
|
65
|
+
else:
|
|
66
|
+
return TrismikRunResults(session.id, results)
|
|
67
|
+
|
|
68
|
+
async def run_replay(self,
|
|
69
|
+
previous_session_id: str,
|
|
70
|
+
session_metadata: TrismikSessionMetadata,
|
|
71
|
+
with_responses: bool = False,
|
|
72
|
+
) -> TrismikRunResults:
|
|
73
|
+
"""
|
|
74
|
+
Replay the exact sequence of questions from a previous session
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
previous_session_id (str): ID of a previous session to replay
|
|
78
|
+
with_responses (bool): If True, responses will be included with the results.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
TrismikRunResults: Either just test results, or with responses.
|
|
82
|
+
|
|
83
|
+
Raises:
|
|
84
|
+
TrismikApiError: If API request fails.
|
|
85
|
+
"""
|
|
86
|
+
await self._init()
|
|
87
|
+
await self._refresh_token_if_needed()
|
|
88
|
+
session = await self._client.create_replay_session(previous_session_id, session_metadata, self._auth.token)
|
|
89
|
+
|
|
90
|
+
await self._run_session(session.url)
|
|
91
|
+
results = await self._client.results(session.url, self._auth.token)
|
|
92
|
+
|
|
93
|
+
if with_responses:
|
|
94
|
+
responses = await self._client.responses(session.url, self._auth.token)
|
|
95
|
+
return TrismikRunResults(session.id, results, responses)
|
|
96
|
+
else:
|
|
97
|
+
return TrismikRunResults(session.id, results)
|
|
98
|
+
|
|
99
|
+
async def _run_session(self, session_url: str) -> None:
|
|
100
|
+
await self._init()
|
|
101
|
+
await self._refresh_token_if_needed()
|
|
102
|
+
item = await self._client.current_item(session_url, self._auth.token)
|
|
103
|
+
while item is not None:
|
|
104
|
+
await self._refresh_token_if_needed()
|
|
105
|
+
response = await self._item_processor(item)
|
|
106
|
+
item = await self._client.respond_to_current_item(
|
|
107
|
+
session_url, response, self._auth.token)
|
|
108
|
+
|
|
109
|
+
async def _init(self) -> None:
|
|
110
|
+
if self._client is None:
|
|
111
|
+
self._client = TrismikAsyncClient()
|
|
112
|
+
|
|
113
|
+
if self._auth is None:
|
|
114
|
+
self._auth = await self._client.authenticate()
|
|
115
|
+
|
|
116
|
+
async def _refresh_token_if_needed(self) -> None:
|
|
117
|
+
if self._token_needs_refresh():
|
|
118
|
+
self._auth = await self._client.refresh_token(self._auth.token)
|
|
119
|
+
|
|
120
|
+
def _token_needs_refresh(self) -> bool:
|
|
121
|
+
return self._auth.expires < (datetime.now() + timedelta(minutes=5))
|