hackerrank 2026.5.12.2__py2.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.
- hackerrank/__init__.py +1 -0
- hackerrank/_dict_types.py +324 -0
- hackerrank/async_client.py +1044 -0
- hackerrank/client.py +2446 -0
- hackerrank/exceptions.py +129 -0
- hackerrank/py.typed +0 -0
- hackerrank/transports.py +263 -0
- hackerrank/types.py +1012 -0
- hackerrank-2026.5.12.2.dist-info/METADATA +117 -0
- hackerrank-2026.5.12.2.dist-info/RECORD +13 -0
- hackerrank-2026.5.12.2.dist-info/WHEEL +6 -0
- hackerrank-2026.5.12.2.dist-info/licenses/LICENSE +21 -0
- hackerrank-2026.5.12.2.dist-info/top_level.txt +1 -0
hackerrank/types.py
ADDED
|
@@ -0,0 +1,1012 @@
|
|
|
1
|
+
"""Types for the HackerRank for Work API."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Iterable, Mapping, Sequence
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import Any, ClassVar, Self
|
|
6
|
+
|
|
7
|
+
from beartype import beartype
|
|
8
|
+
|
|
9
|
+
from hackerrank._dict_types import (
|
|
10
|
+
ATSCodePairDict,
|
|
11
|
+
ATSCodeScreenDict,
|
|
12
|
+
AuditLogDict,
|
|
13
|
+
CandidateDetailDict,
|
|
14
|
+
InterviewDict,
|
|
15
|
+
InterviewTemplateDict,
|
|
16
|
+
InterviewTranscriptDict,
|
|
17
|
+
InterviewTranscriptMessageDict,
|
|
18
|
+
InviterDict,
|
|
19
|
+
QuestionDict,
|
|
20
|
+
SCIMTeamDict,
|
|
21
|
+
SCIMUserDict,
|
|
22
|
+
TeamDict,
|
|
23
|
+
TemplateDict,
|
|
24
|
+
TestCandidateDict,
|
|
25
|
+
TestDict,
|
|
26
|
+
UserDict,
|
|
27
|
+
UserTeamMembershipDict,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
type JSONValue = (
|
|
31
|
+
str | int | float | bool | None | Sequence[Any] | Mapping[str, Any]
|
|
32
|
+
)
|
|
33
|
+
"""A JSON-compatible value.
|
|
34
|
+
|
|
35
|
+
Used for free-form fields such as ``metadata``, ``candidate``,
|
|
36
|
+
``accommodations`` and ``webhook_authentication`` — anything where
|
|
37
|
+
the HackerRank API accepts or returns an opaque blob constrained
|
|
38
|
+
only to be JSON-serialisable.
|
|
39
|
+
|
|
40
|
+
``Sequence`` / ``Mapping`` (rather than ``list`` / ``dict``) make
|
|
41
|
+
the alias accept narrower concrete types such as ``dict[str, str]``
|
|
42
|
+
without invariance issues. The inner ``Any`` keeps the alias
|
|
43
|
+
non-recursive so ``@beartype`` can resolve it at runtime.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@beartype
|
|
48
|
+
class Page[T](list[T]):
|
|
49
|
+
"""A page of results with HackerRank's pagination metadata."""
|
|
50
|
+
|
|
51
|
+
def __init__(
|
|
52
|
+
self,
|
|
53
|
+
iterable: Iterable[T] = (),
|
|
54
|
+
/,
|
|
55
|
+
*,
|
|
56
|
+
page_total: int,
|
|
57
|
+
offset: int,
|
|
58
|
+
previous: str,
|
|
59
|
+
next_: str,
|
|
60
|
+
first: str,
|
|
61
|
+
last: str,
|
|
62
|
+
total: int,
|
|
63
|
+
) -> None:
|
|
64
|
+
"""Create a new page.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
iterable: The items for the list.
|
|
68
|
+
page_total: Count of items in the current page.
|
|
69
|
+
offset: The offset of the current page.
|
|
70
|
+
previous: URL of the previous page.
|
|
71
|
+
next_: URL of the next page.
|
|
72
|
+
first: URL of the first page.
|
|
73
|
+
last: URL of the last page.
|
|
74
|
+
total: Total number of items across all pages.
|
|
75
|
+
"""
|
|
76
|
+
super().__init__(iterable)
|
|
77
|
+
self.page_total = page_total
|
|
78
|
+
self.offset = offset
|
|
79
|
+
self.previous = previous
|
|
80
|
+
self.next = next_
|
|
81
|
+
self.first = first
|
|
82
|
+
self.last = last
|
|
83
|
+
self.total = total
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def data(self) -> list[T]:
|
|
87
|
+
"""Return the items as a plain list.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
A copy of the items in this page.
|
|
91
|
+
"""
|
|
92
|
+
return list(self)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@beartype
|
|
96
|
+
class SCIMPage[T](list[T]):
|
|
97
|
+
"""A SCIM v2 paginated response.
|
|
98
|
+
|
|
99
|
+
SCIM uses a different envelope from the v3 API.
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
def __init__(
|
|
103
|
+
self,
|
|
104
|
+
iterable: Iterable[T] = (),
|
|
105
|
+
/,
|
|
106
|
+
*,
|
|
107
|
+
schemas: list[str],
|
|
108
|
+
start_index: int,
|
|
109
|
+
items_per_page: int,
|
|
110
|
+
total_results: int,
|
|
111
|
+
) -> None:
|
|
112
|
+
"""Create a new SCIM page.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
iterable: The items for the list.
|
|
116
|
+
schemas: The SCIM schemas for the response.
|
|
117
|
+
start_index: 1-based index of the first item.
|
|
118
|
+
items_per_page: Number of items per page.
|
|
119
|
+
total_results: Total number of items.
|
|
120
|
+
"""
|
|
121
|
+
super().__init__(iterable)
|
|
122
|
+
self.schemas = schemas
|
|
123
|
+
self.start_index = start_index
|
|
124
|
+
self.items_per_page = items_per_page
|
|
125
|
+
self.total_results = total_results
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@beartype
|
|
129
|
+
@dataclass(frozen=True, kw_only=True)
|
|
130
|
+
class CandidateDetail:
|
|
131
|
+
"""A custom candidate detail field."""
|
|
132
|
+
|
|
133
|
+
field_name: str
|
|
134
|
+
title: str
|
|
135
|
+
value: str
|
|
136
|
+
|
|
137
|
+
@classmethod
|
|
138
|
+
def from_dict(cls, data: CandidateDetailDict) -> Self:
|
|
139
|
+
"""Create from an API response dictionary.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
data: The dictionary to convert.
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
A new instance.
|
|
146
|
+
"""
|
|
147
|
+
return cls(
|
|
148
|
+
field_name=data["field_name"],
|
|
149
|
+
title=data["title"],
|
|
150
|
+
value=data["value"],
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
@beartype
|
|
155
|
+
@dataclass(frozen=True, kw_only=True)
|
|
156
|
+
class Interview:
|
|
157
|
+
"""A HackerRank interview."""
|
|
158
|
+
|
|
159
|
+
id: str
|
|
160
|
+
status: str
|
|
161
|
+
url: str
|
|
162
|
+
title: str | None = None
|
|
163
|
+
feedback: str | None = None
|
|
164
|
+
thumbs_up: int | None = None
|
|
165
|
+
notes: str | None = None
|
|
166
|
+
resume_url: str | None = None
|
|
167
|
+
interviewers: list[str] | None = None
|
|
168
|
+
result_url: str | None = None
|
|
169
|
+
candidate: dict[str, JSONValue] | None = None
|
|
170
|
+
metadata: dict[str, JSONValue] | None = None
|
|
171
|
+
report_url: str | None = None
|
|
172
|
+
ended_at: str | None = None
|
|
173
|
+
interview_template_id: int | None = None
|
|
174
|
+
created_at: str | None = None
|
|
175
|
+
updated_at: str | None = None
|
|
176
|
+
user: int | None = None
|
|
177
|
+
send_email: bool | None = None
|
|
178
|
+
|
|
179
|
+
@classmethod
|
|
180
|
+
def from_dict(cls, data: InterviewDict) -> Self:
|
|
181
|
+
"""Create from an API response dictionary.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
data: The dictionary to convert.
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
A new instance.
|
|
188
|
+
"""
|
|
189
|
+
return cls(
|
|
190
|
+
id=data["id"],
|
|
191
|
+
status=data["status"],
|
|
192
|
+
url=data["url"],
|
|
193
|
+
title=data.get("title"),
|
|
194
|
+
feedback=data.get("feedback"),
|
|
195
|
+
thumbs_up=data.get("thumbs_up"),
|
|
196
|
+
notes=data.get("notes"),
|
|
197
|
+
resume_url=data.get("resume_url"),
|
|
198
|
+
interviewers=data.get("interviewers"),
|
|
199
|
+
result_url=data.get("result_url"),
|
|
200
|
+
candidate=data.get("candidate"),
|
|
201
|
+
metadata=data.get("metadata"),
|
|
202
|
+
report_url=data.get("report_url"),
|
|
203
|
+
ended_at=data.get("ended_at"),
|
|
204
|
+
interview_template_id=data.get(
|
|
205
|
+
"interview_template_id",
|
|
206
|
+
),
|
|
207
|
+
created_at=data.get("created_at"),
|
|
208
|
+
updated_at=data.get("updated_at"),
|
|
209
|
+
user=data.get("user"),
|
|
210
|
+
send_email=data.get("send_email"),
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
@beartype
|
|
215
|
+
@dataclass(frozen=True, kw_only=True)
|
|
216
|
+
class InterviewTranscriptMessage:
|
|
217
|
+
"""A single message in an interview transcript."""
|
|
218
|
+
|
|
219
|
+
author: str
|
|
220
|
+
timestamp: int
|
|
221
|
+
text: str
|
|
222
|
+
candidate: bool
|
|
223
|
+
message_id: str
|
|
224
|
+
email: str | None = None
|
|
225
|
+
|
|
226
|
+
@classmethod
|
|
227
|
+
def from_dict(
|
|
228
|
+
cls,
|
|
229
|
+
data: InterviewTranscriptMessageDict,
|
|
230
|
+
) -> Self:
|
|
231
|
+
"""Create from an API response dictionary.
|
|
232
|
+
|
|
233
|
+
Args:
|
|
234
|
+
data: The dictionary to convert.
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
A new instance.
|
|
238
|
+
"""
|
|
239
|
+
return cls(
|
|
240
|
+
author=data["author"],
|
|
241
|
+
timestamp=data["timestamp"],
|
|
242
|
+
text=data["text"],
|
|
243
|
+
candidate=data["candidate"],
|
|
244
|
+
message_id=data["messageId"],
|
|
245
|
+
email=data.get("email"),
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
@beartype
|
|
250
|
+
@dataclass(frozen=True, kw_only=True)
|
|
251
|
+
class InterviewTranscript:
|
|
252
|
+
"""The transcript for an interview."""
|
|
253
|
+
|
|
254
|
+
messages: list[InterviewTranscriptMessage]
|
|
255
|
+
|
|
256
|
+
@classmethod
|
|
257
|
+
def from_dict(cls, data: InterviewTranscriptDict) -> Self:
|
|
258
|
+
"""Create from an API response dictionary.
|
|
259
|
+
|
|
260
|
+
Args:
|
|
261
|
+
data: The dictionary to convert.
|
|
262
|
+
|
|
263
|
+
Returns:
|
|
264
|
+
A new instance.
|
|
265
|
+
"""
|
|
266
|
+
return cls(
|
|
267
|
+
messages=[
|
|
268
|
+
InterviewTranscriptMessage.from_dict(data=m)
|
|
269
|
+
for m in data["messages"]
|
|
270
|
+
],
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
@beartype
|
|
275
|
+
@dataclass(frozen=True, kw_only=True)
|
|
276
|
+
class InterviewTemplate:
|
|
277
|
+
"""A HackerRank interview template."""
|
|
278
|
+
|
|
279
|
+
id: int
|
|
280
|
+
name: str
|
|
281
|
+
created_at: str | None = None
|
|
282
|
+
status: int | None = None
|
|
283
|
+
user: int | None = None
|
|
284
|
+
roles: list[str] | None = None
|
|
285
|
+
team_share: int | None = None
|
|
286
|
+
questions: list[str] | None = None
|
|
287
|
+
scorecard: int | None = None
|
|
288
|
+
import_template: bool | None = None
|
|
289
|
+
editor_access: bool | None = None
|
|
290
|
+
|
|
291
|
+
@classmethod
|
|
292
|
+
def from_dict(cls, data: InterviewTemplateDict) -> Self:
|
|
293
|
+
"""Create from an API response dictionary.
|
|
294
|
+
|
|
295
|
+
Args:
|
|
296
|
+
data: The dictionary to convert.
|
|
297
|
+
|
|
298
|
+
Returns:
|
|
299
|
+
A new instance.
|
|
300
|
+
"""
|
|
301
|
+
return cls(
|
|
302
|
+
id=data["id"],
|
|
303
|
+
name=data["name"],
|
|
304
|
+
created_at=data.get("created_at"),
|
|
305
|
+
status=data.get("status"),
|
|
306
|
+
user=data.get("user"),
|
|
307
|
+
roles=data.get("roles"),
|
|
308
|
+
team_share=data.get("team_share"),
|
|
309
|
+
questions=data.get("questions"),
|
|
310
|
+
scorecard=data.get("scorecard"),
|
|
311
|
+
import_template=data.get("import_template"),
|
|
312
|
+
editor_access=data.get("editor_access"),
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
@beartype
|
|
317
|
+
@dataclass(frozen=True, kw_only=True)
|
|
318
|
+
class Question:
|
|
319
|
+
"""A HackerRank question."""
|
|
320
|
+
|
|
321
|
+
id: str
|
|
322
|
+
type: str
|
|
323
|
+
name: str
|
|
324
|
+
unique_id: str | None = None
|
|
325
|
+
owner: str | None = None
|
|
326
|
+
created_at: str | None = None
|
|
327
|
+
status: str | None = None
|
|
328
|
+
internal_notes: str | None = None
|
|
329
|
+
languages: list[str] | None = None
|
|
330
|
+
problem_statement: str | None = None
|
|
331
|
+
recommended_duration: int | None = None
|
|
332
|
+
tags: list[str] | None = None
|
|
333
|
+
max_score: float | None = None
|
|
334
|
+
options: list[str] | None = None
|
|
335
|
+
answer: int | list[int] | None = None
|
|
336
|
+
|
|
337
|
+
@classmethod
|
|
338
|
+
def from_dict(cls, data: QuestionDict) -> Self:
|
|
339
|
+
"""Create from an API response dictionary.
|
|
340
|
+
|
|
341
|
+
Args:
|
|
342
|
+
data: The dictionary to convert.
|
|
343
|
+
|
|
344
|
+
Returns:
|
|
345
|
+
A new instance.
|
|
346
|
+
"""
|
|
347
|
+
return cls(
|
|
348
|
+
id=data["id"],
|
|
349
|
+
type=data["type"],
|
|
350
|
+
name=data["name"],
|
|
351
|
+
unique_id=data.get("unique_id"),
|
|
352
|
+
owner=data.get("owner"),
|
|
353
|
+
created_at=data.get("created_at"),
|
|
354
|
+
status=data.get("status"),
|
|
355
|
+
internal_notes=data.get("internal_notes"),
|
|
356
|
+
languages=data.get("languages"),
|
|
357
|
+
problem_statement=data.get("problem_statement"),
|
|
358
|
+
recommended_duration=data.get(
|
|
359
|
+
"recommended_duration",
|
|
360
|
+
),
|
|
361
|
+
tags=data.get("tags"),
|
|
362
|
+
max_score=data.get("max_score"),
|
|
363
|
+
options=data.get("options"),
|
|
364
|
+
answer=data.get("answer"),
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
@beartype
|
|
369
|
+
@dataclass(frozen=True, kw_only=True)
|
|
370
|
+
class Test:
|
|
371
|
+
"""A HackerRank test."""
|
|
372
|
+
|
|
373
|
+
__test__: ClassVar[bool] = False
|
|
374
|
+
|
|
375
|
+
id: str
|
|
376
|
+
name: str
|
|
377
|
+
unique_id: str | None = None
|
|
378
|
+
starttime: str | None = None
|
|
379
|
+
endtime: str | None = None
|
|
380
|
+
duration: int | None = None
|
|
381
|
+
owner: str | None = None
|
|
382
|
+
instructions: str | None = None
|
|
383
|
+
starred: bool | None = None
|
|
384
|
+
created_at: str | None = None
|
|
385
|
+
state: str | None = None
|
|
386
|
+
locked: bool | None = None
|
|
387
|
+
draft: bool | None = None
|
|
388
|
+
languages: list[str] | None = None
|
|
389
|
+
candidate_details: list[str] | None = None
|
|
390
|
+
custom_acknowledge_text: str | None = None
|
|
391
|
+
cutoff_score: int | None = None
|
|
392
|
+
master_password: str | None = None
|
|
393
|
+
hide_compile_test: bool | None = None
|
|
394
|
+
tags: list[str] | None = None
|
|
395
|
+
role_ids: list[str] | None = None
|
|
396
|
+
experience: list[str] | None = None
|
|
397
|
+
questions: list[str] | None = None
|
|
398
|
+
sections: list[dict[str, JSONValue]] | None = None
|
|
399
|
+
mcq_incorrect_score: int | None = None
|
|
400
|
+
mcq_correct_score: int | None = None
|
|
401
|
+
locked_by: str | None = None
|
|
402
|
+
short_login_url: str | None = None
|
|
403
|
+
public_login_url: str | None = None
|
|
404
|
+
shuffle_questions: bool | None = None
|
|
405
|
+
test_admins: list[str] | None = None
|
|
406
|
+
hide_template: bool | None = None
|
|
407
|
+
enable_acknowledgement: bool | None = None
|
|
408
|
+
enable_proctoring: bool | None = None
|
|
409
|
+
enable_advanced_proctoring: bool | None = None
|
|
410
|
+
enable_secure_assessment_mode: bool | None = None
|
|
411
|
+
enable_ml_plagiarism_analysis: bool | None = None
|
|
412
|
+
enable_photo_identification: bool | None = None
|
|
413
|
+
ide_config: str | None = None
|
|
414
|
+
|
|
415
|
+
@classmethod
|
|
416
|
+
def from_dict(cls, data: TestDict) -> Self:
|
|
417
|
+
"""Create from an API response dictionary.
|
|
418
|
+
|
|
419
|
+
Args:
|
|
420
|
+
data: The dictionary to convert.
|
|
421
|
+
|
|
422
|
+
Returns:
|
|
423
|
+
A new instance.
|
|
424
|
+
"""
|
|
425
|
+
return cls(
|
|
426
|
+
id=data["id"],
|
|
427
|
+
name=data["name"],
|
|
428
|
+
unique_id=data.get("unique_id"),
|
|
429
|
+
starttime=data.get("starttime"),
|
|
430
|
+
endtime=data.get("endtime"),
|
|
431
|
+
duration=data.get("duration"),
|
|
432
|
+
owner=data.get("owner"),
|
|
433
|
+
instructions=data.get("instructions"),
|
|
434
|
+
starred=data.get("starred"),
|
|
435
|
+
created_at=data.get("created_at"),
|
|
436
|
+
state=data.get("state"),
|
|
437
|
+
locked=data.get("locked"),
|
|
438
|
+
draft=data.get("draft"),
|
|
439
|
+
languages=data.get("languages"),
|
|
440
|
+
candidate_details=data.get("candidate_details"),
|
|
441
|
+
custom_acknowledge_text=data.get(
|
|
442
|
+
"custom_acknowledge_text",
|
|
443
|
+
),
|
|
444
|
+
cutoff_score=data.get("cutoff_score"),
|
|
445
|
+
master_password=data.get("master_password"),
|
|
446
|
+
hide_compile_test=data.get("hide_compile_test"),
|
|
447
|
+
tags=data.get("tags"),
|
|
448
|
+
role_ids=data.get("role_ids"),
|
|
449
|
+
experience=data.get("experience"),
|
|
450
|
+
questions=data.get("questions"),
|
|
451
|
+
sections=data.get("sections"),
|
|
452
|
+
mcq_incorrect_score=data.get("mcq_incorrect_score"),
|
|
453
|
+
mcq_correct_score=data.get("mcq_correct_score"),
|
|
454
|
+
locked_by=data.get("locked_by"),
|
|
455
|
+
short_login_url=data.get("short_login_url"),
|
|
456
|
+
public_login_url=data.get("public_login_url"),
|
|
457
|
+
shuffle_questions=data.get("shuffle_questions"),
|
|
458
|
+
test_admins=data.get("test_admins"),
|
|
459
|
+
hide_template=data.get("hide_template"),
|
|
460
|
+
enable_acknowledgement=data.get(
|
|
461
|
+
"enable_acknowledgement",
|
|
462
|
+
),
|
|
463
|
+
enable_proctoring=data.get("enable_proctoring"),
|
|
464
|
+
enable_advanced_proctoring=data.get(
|
|
465
|
+
"enable_advanced_proctoring",
|
|
466
|
+
),
|
|
467
|
+
enable_secure_assessment_mode=data.get(
|
|
468
|
+
"enable_secure_assessment_mode",
|
|
469
|
+
),
|
|
470
|
+
enable_ml_plagiarism_analysis=data.get(
|
|
471
|
+
"enable_ml_plagiarism_analysis",
|
|
472
|
+
),
|
|
473
|
+
enable_photo_identification=data.get(
|
|
474
|
+
"enable_photo_identification",
|
|
475
|
+
),
|
|
476
|
+
ide_config=data.get("ide_config"),
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
@beartype
|
|
481
|
+
@dataclass(frozen=True, kw_only=True)
|
|
482
|
+
class TestCandidate:
|
|
483
|
+
"""A candidate associated with a test."""
|
|
484
|
+
|
|
485
|
+
__test__: ClassVar[bool] = False
|
|
486
|
+
|
|
487
|
+
id: str
|
|
488
|
+
email: str
|
|
489
|
+
full_name: str | None = None
|
|
490
|
+
score: float | None = None
|
|
491
|
+
test: str | None = None
|
|
492
|
+
user: str | None = None
|
|
493
|
+
attempt_starttime: str | None = None
|
|
494
|
+
attempt_endtime: str | None = None
|
|
495
|
+
attempt_events: list[str] | None = None
|
|
496
|
+
status: int | None = None
|
|
497
|
+
ats_state: int | None = None
|
|
498
|
+
integrity_status: str | None = None
|
|
499
|
+
integrity_summary: str | None = None
|
|
500
|
+
invite_email_done: bool | None = None
|
|
501
|
+
invite_valid: bool | None = None
|
|
502
|
+
invited_on: str | None = None
|
|
503
|
+
invite_valid_from: str | None = None
|
|
504
|
+
invite_valid_to: str | None = None
|
|
505
|
+
invite_link: str | None = None
|
|
506
|
+
invite_metadata: dict[str, JSONValue] | None = None
|
|
507
|
+
evaluator_email: str | None = None
|
|
508
|
+
test_finish_url: str | None = None
|
|
509
|
+
test_result_url: str | None = None
|
|
510
|
+
accept_result_updates: bool | None = None
|
|
511
|
+
tags: list[str] | None = None
|
|
512
|
+
report_url: str | None = None
|
|
513
|
+
authenticated_report_url: str | None = None
|
|
514
|
+
pdf_url: str | None = None
|
|
515
|
+
scores_tags_split: dict[str, JSONValue] | None = None
|
|
516
|
+
scores_skills_split: dict[str, JSONValue] | None = None
|
|
517
|
+
added_time: int | None = None
|
|
518
|
+
unclaimed_added_time: int | None = None
|
|
519
|
+
comments: dict[str, JSONValue] | None = None
|
|
520
|
+
performance_summary: str | None = None
|
|
521
|
+
ip_address: str | None = None
|
|
522
|
+
questions: dict[str, JSONValue] | None = None
|
|
523
|
+
plagiarism: dict[str, JSONValue] | None = None
|
|
524
|
+
plagiarism_status: bool | None = None
|
|
525
|
+
max_code_similarity: dict[str, JSONValue] | None = None
|
|
526
|
+
feedback: str | None = None
|
|
527
|
+
percentage_score: float | None = None
|
|
528
|
+
candidate_details: list[CandidateDetail] | None = None
|
|
529
|
+
out_of_window_events: int | None = None
|
|
530
|
+
out_of_window_duration: float | None = None
|
|
531
|
+
editor_paste_count: int | None = None
|
|
532
|
+
proctor_images: list[str] | None = None
|
|
533
|
+
|
|
534
|
+
@classmethod
|
|
535
|
+
def from_dict(cls, data: TestCandidateDict) -> Self:
|
|
536
|
+
"""Create from an API response dictionary.
|
|
537
|
+
|
|
538
|
+
Args:
|
|
539
|
+
data: The dictionary to convert.
|
|
540
|
+
|
|
541
|
+
Returns:
|
|
542
|
+
A new instance.
|
|
543
|
+
"""
|
|
544
|
+
raw_details = data.get("candidate_details")
|
|
545
|
+
return cls(
|
|
546
|
+
id=data["id"],
|
|
547
|
+
email=data["email"],
|
|
548
|
+
full_name=data.get("full_name"),
|
|
549
|
+
score=data.get("score"),
|
|
550
|
+
test=data.get("test"),
|
|
551
|
+
user=data.get("user"),
|
|
552
|
+
attempt_starttime=data.get("attempt_starttime"),
|
|
553
|
+
attempt_endtime=data.get("attempt_endtime"),
|
|
554
|
+
attempt_events=data.get("attempt_events"),
|
|
555
|
+
status=data.get("status"),
|
|
556
|
+
ats_state=data.get("ats_state"),
|
|
557
|
+
integrity_status=data.get("integrity_status"),
|
|
558
|
+
integrity_summary=data.get("integrity_summary"),
|
|
559
|
+
invite_email_done=data.get("invite_email_done"),
|
|
560
|
+
invite_valid=data.get("invite_valid"),
|
|
561
|
+
invited_on=data.get("invited_on"),
|
|
562
|
+
invite_valid_from=data.get("invite_valid_from"),
|
|
563
|
+
invite_valid_to=data.get("invite_valid_to"),
|
|
564
|
+
invite_link=data.get("invite_link"),
|
|
565
|
+
invite_metadata=data.get("invite_metadata"),
|
|
566
|
+
evaluator_email=data.get("evaluator_email"),
|
|
567
|
+
test_finish_url=data.get("test_finish_url"),
|
|
568
|
+
test_result_url=data.get("test_result_url"),
|
|
569
|
+
accept_result_updates=data.get(
|
|
570
|
+
"accept_result_updates",
|
|
571
|
+
),
|
|
572
|
+
tags=data.get("tags"),
|
|
573
|
+
report_url=data.get("report_url"),
|
|
574
|
+
authenticated_report_url=data.get(
|
|
575
|
+
"authenticated_report_url",
|
|
576
|
+
),
|
|
577
|
+
pdf_url=data.get("pdf_url"),
|
|
578
|
+
scores_tags_split=data.get("scores_tags_split"),
|
|
579
|
+
scores_skills_split=data.get(
|
|
580
|
+
"scores_skills_split",
|
|
581
|
+
),
|
|
582
|
+
added_time=data.get("added_time"),
|
|
583
|
+
unclaimed_added_time=data.get(
|
|
584
|
+
"unclaimed_added_time",
|
|
585
|
+
),
|
|
586
|
+
comments=data.get("comments"),
|
|
587
|
+
performance_summary=data.get("performance_summary"),
|
|
588
|
+
ip_address=data.get("ip_address"),
|
|
589
|
+
questions=data.get("questions"),
|
|
590
|
+
plagiarism=data.get("plagiarism"),
|
|
591
|
+
plagiarism_status=data.get("plagiarism_status"),
|
|
592
|
+
max_code_similarity=data.get(
|
|
593
|
+
"max_code_similarity",
|
|
594
|
+
),
|
|
595
|
+
feedback=data.get("feedback"),
|
|
596
|
+
percentage_score=data.get("percentage_score"),
|
|
597
|
+
candidate_details=[
|
|
598
|
+
CandidateDetail.from_dict(data=item) for item in raw_details
|
|
599
|
+
]
|
|
600
|
+
if raw_details is not None
|
|
601
|
+
else None,
|
|
602
|
+
out_of_window_events=data.get(
|
|
603
|
+
"out_of_window_events",
|
|
604
|
+
),
|
|
605
|
+
out_of_window_duration=data.get(
|
|
606
|
+
"out_of_window_duration",
|
|
607
|
+
),
|
|
608
|
+
editor_paste_count=data.get("editor_paste_count"),
|
|
609
|
+
proctor_images=data.get("proctor_images"),
|
|
610
|
+
)
|
|
611
|
+
|
|
612
|
+
|
|
613
|
+
@beartype
|
|
614
|
+
@dataclass(frozen=True, kw_only=True)
|
|
615
|
+
class Inviter:
|
|
616
|
+
"""A user permitted to invite candidates to a test."""
|
|
617
|
+
|
|
618
|
+
id: str
|
|
619
|
+
email: str
|
|
620
|
+
firstname: str | None = None
|
|
621
|
+
lastname: str | None = None
|
|
622
|
+
role: str | None = None
|
|
623
|
+
status: str | None = None
|
|
624
|
+
phone: str | None = None
|
|
625
|
+
timezone: str | None = None
|
|
626
|
+
questions_permission: int | None = None
|
|
627
|
+
tests_permission: int | None = None
|
|
628
|
+
interviews_permission: int | None = None
|
|
629
|
+
candidates_permission: int | None = None
|
|
630
|
+
teams: list[str] | None = None
|
|
631
|
+
candidates_invited: int | None = None
|
|
632
|
+
activated: bool | None = None
|
|
633
|
+
|
|
634
|
+
@classmethod
|
|
635
|
+
def from_dict(cls, data: InviterDict) -> Self:
|
|
636
|
+
"""Create from an API response dictionary.
|
|
637
|
+
|
|
638
|
+
Args:
|
|
639
|
+
data: The dictionary to convert.
|
|
640
|
+
|
|
641
|
+
Returns:
|
|
642
|
+
A new instance.
|
|
643
|
+
"""
|
|
644
|
+
return cls(
|
|
645
|
+
id=data["id"],
|
|
646
|
+
email=data["email"],
|
|
647
|
+
firstname=data.get("firstname"),
|
|
648
|
+
lastname=data.get("lastname"),
|
|
649
|
+
role=data.get("role"),
|
|
650
|
+
status=data.get("status"),
|
|
651
|
+
phone=data.get("phone"),
|
|
652
|
+
timezone=data.get("timezone"),
|
|
653
|
+
questions_permission=data.get(
|
|
654
|
+
"questions_permission",
|
|
655
|
+
),
|
|
656
|
+
tests_permission=data.get("tests_permission"),
|
|
657
|
+
interviews_permission=data.get(
|
|
658
|
+
"interviews_permission",
|
|
659
|
+
),
|
|
660
|
+
candidates_permission=data.get(
|
|
661
|
+
"candidates_permission",
|
|
662
|
+
),
|
|
663
|
+
teams=data.get("teams"),
|
|
664
|
+
candidates_invited=data.get("candidates_invited"),
|
|
665
|
+
activated=data.get("activated"),
|
|
666
|
+
)
|
|
667
|
+
|
|
668
|
+
|
|
669
|
+
@beartype
|
|
670
|
+
@dataclass(frozen=True, kw_only=True)
|
|
671
|
+
class User:
|
|
672
|
+
"""A HackerRank user."""
|
|
673
|
+
|
|
674
|
+
id: str
|
|
675
|
+
email: str
|
|
676
|
+
firstname: str | None = None
|
|
677
|
+
lastname: str | None = None
|
|
678
|
+
country: str | None = None
|
|
679
|
+
role: str | None = None
|
|
680
|
+
status: str | None = None
|
|
681
|
+
phone: str | None = None
|
|
682
|
+
timezone: str | None = None
|
|
683
|
+
questions_permission: int | None = None
|
|
684
|
+
tests_permission: int | None = None
|
|
685
|
+
interviews_permission: int | None = None
|
|
686
|
+
candidates_permission: int | None = None
|
|
687
|
+
shared_questions_permission: int | None = None
|
|
688
|
+
shared_tests_permission: int | None = None
|
|
689
|
+
shared_interviews_permission: int | None = None
|
|
690
|
+
shared_candidates_permission: int | None = None
|
|
691
|
+
company_admin: bool | None = None
|
|
692
|
+
team_admin: bool | None = None
|
|
693
|
+
teams: list[str] | None = None
|
|
694
|
+
activated: bool | None = None
|
|
695
|
+
last_activity_time: str | None = None
|
|
696
|
+
|
|
697
|
+
@classmethod
|
|
698
|
+
def from_dict(cls, data: UserDict) -> Self:
|
|
699
|
+
"""Create from an API response dictionary.
|
|
700
|
+
|
|
701
|
+
Args:
|
|
702
|
+
data: The dictionary to convert.
|
|
703
|
+
|
|
704
|
+
Returns:
|
|
705
|
+
A new instance.
|
|
706
|
+
"""
|
|
707
|
+
return cls(
|
|
708
|
+
id=data["id"],
|
|
709
|
+
email=data["email"],
|
|
710
|
+
firstname=data.get("firstname"),
|
|
711
|
+
lastname=data.get("lastname"),
|
|
712
|
+
country=data.get("country"),
|
|
713
|
+
role=data.get("role"),
|
|
714
|
+
status=data.get("status"),
|
|
715
|
+
phone=data.get("phone"),
|
|
716
|
+
timezone=data.get("timezone"),
|
|
717
|
+
questions_permission=data.get(
|
|
718
|
+
"questions_permission",
|
|
719
|
+
),
|
|
720
|
+
tests_permission=data.get("tests_permission"),
|
|
721
|
+
interviews_permission=data.get(
|
|
722
|
+
"interviews_permission",
|
|
723
|
+
),
|
|
724
|
+
candidates_permission=data.get(
|
|
725
|
+
"candidates_permission",
|
|
726
|
+
),
|
|
727
|
+
shared_questions_permission=data.get(
|
|
728
|
+
"shared_questions_permission",
|
|
729
|
+
),
|
|
730
|
+
shared_tests_permission=data.get(
|
|
731
|
+
"shared_tests_permission",
|
|
732
|
+
),
|
|
733
|
+
shared_interviews_permission=data.get(
|
|
734
|
+
"shared_interviews_permission",
|
|
735
|
+
),
|
|
736
|
+
shared_candidates_permission=data.get(
|
|
737
|
+
"shared_candidates_permission",
|
|
738
|
+
),
|
|
739
|
+
company_admin=data.get("company_admin"),
|
|
740
|
+
team_admin=data.get("team_admin"),
|
|
741
|
+
teams=data.get("teams"),
|
|
742
|
+
activated=data.get("activated"),
|
|
743
|
+
last_activity_time=data.get("last_activity_time"),
|
|
744
|
+
)
|
|
745
|
+
|
|
746
|
+
|
|
747
|
+
@beartype
|
|
748
|
+
@dataclass(frozen=True, kw_only=True)
|
|
749
|
+
class Team:
|
|
750
|
+
"""A HackerRank team."""
|
|
751
|
+
|
|
752
|
+
id: str
|
|
753
|
+
name: str
|
|
754
|
+
owner: str | None = None
|
|
755
|
+
created_at: str | None = None
|
|
756
|
+
recruiter_count: int | None = None
|
|
757
|
+
developer_count: int | None = None
|
|
758
|
+
recruiter_cap: int | None = None
|
|
759
|
+
developer_cap: int | None = None
|
|
760
|
+
invite_as: str | None = None
|
|
761
|
+
locations: list[str] | None = None
|
|
762
|
+
departments: list[str] | None = None
|
|
763
|
+
|
|
764
|
+
@classmethod
|
|
765
|
+
def from_dict(cls, data: TeamDict) -> Self:
|
|
766
|
+
"""Create from an API response dictionary.
|
|
767
|
+
|
|
768
|
+
Args:
|
|
769
|
+
data: The dictionary to convert.
|
|
770
|
+
|
|
771
|
+
Returns:
|
|
772
|
+
A new instance.
|
|
773
|
+
"""
|
|
774
|
+
return cls(
|
|
775
|
+
id=data["id"],
|
|
776
|
+
name=data["name"],
|
|
777
|
+
owner=data.get("owner"),
|
|
778
|
+
created_at=data.get("created_at"),
|
|
779
|
+
recruiter_count=data.get("recruiter_count"),
|
|
780
|
+
developer_count=data.get("developer_count"),
|
|
781
|
+
recruiter_cap=data.get("recruiter_cap"),
|
|
782
|
+
developer_cap=data.get("developer_cap"),
|
|
783
|
+
invite_as=data.get("invite_as"),
|
|
784
|
+
locations=data.get("locations"),
|
|
785
|
+
departments=data.get("departments"),
|
|
786
|
+
)
|
|
787
|
+
|
|
788
|
+
|
|
789
|
+
@beartype
|
|
790
|
+
@dataclass(frozen=True, kw_only=True)
|
|
791
|
+
class UserTeamMembership:
|
|
792
|
+
"""A membership of a user in a team."""
|
|
793
|
+
|
|
794
|
+
team: str
|
|
795
|
+
user: str
|
|
796
|
+
|
|
797
|
+
@classmethod
|
|
798
|
+
def from_dict(cls, data: UserTeamMembershipDict) -> Self:
|
|
799
|
+
"""Create from an API response dictionary.
|
|
800
|
+
|
|
801
|
+
Args:
|
|
802
|
+
data: The dictionary to convert.
|
|
803
|
+
|
|
804
|
+
Returns:
|
|
805
|
+
A new instance.
|
|
806
|
+
"""
|
|
807
|
+
return cls(
|
|
808
|
+
team=data["team"],
|
|
809
|
+
user=data["user"],
|
|
810
|
+
)
|
|
811
|
+
|
|
812
|
+
|
|
813
|
+
@beartype
|
|
814
|
+
@dataclass(frozen=True, kw_only=True)
|
|
815
|
+
class Template:
|
|
816
|
+
"""An invite-email template."""
|
|
817
|
+
|
|
818
|
+
id: str
|
|
819
|
+
name: str
|
|
820
|
+
subject: str | None = None
|
|
821
|
+
content: str | None = None
|
|
822
|
+
default: bool | None = None
|
|
823
|
+
created_at: str | None = None
|
|
824
|
+
updated_at: str | None = None
|
|
825
|
+
user: str | None = None
|
|
826
|
+
|
|
827
|
+
@classmethod
|
|
828
|
+
def from_dict(cls, data: TemplateDict) -> Self:
|
|
829
|
+
"""Create from an API response dictionary.
|
|
830
|
+
|
|
831
|
+
Args:
|
|
832
|
+
data: The dictionary to convert.
|
|
833
|
+
|
|
834
|
+
Returns:
|
|
835
|
+
A new instance.
|
|
836
|
+
"""
|
|
837
|
+
return cls(
|
|
838
|
+
id=data["id"],
|
|
839
|
+
name=data["name"],
|
|
840
|
+
subject=data.get("subject"),
|
|
841
|
+
content=data.get("content"),
|
|
842
|
+
default=data.get("default"),
|
|
843
|
+
created_at=data.get("created_at"),
|
|
844
|
+
updated_at=data.get("updated_at"),
|
|
845
|
+
user=data.get("user"),
|
|
846
|
+
)
|
|
847
|
+
|
|
848
|
+
|
|
849
|
+
@beartype
|
|
850
|
+
@dataclass(frozen=True, kw_only=True)
|
|
851
|
+
class AuditLog:
|
|
852
|
+
"""An audit log entry."""
|
|
853
|
+
|
|
854
|
+
source_id: int
|
|
855
|
+
source_type: str
|
|
856
|
+
action: str
|
|
857
|
+
user: str | None = None
|
|
858
|
+
modified_fields: list[str] | None = None
|
|
859
|
+
modified_values: dict[str, JSONValue] | None = None
|
|
860
|
+
ip_address: str | None = None
|
|
861
|
+
created_at: str | None = None
|
|
862
|
+
|
|
863
|
+
@classmethod
|
|
864
|
+
def from_dict(cls, data: AuditLogDict) -> Self:
|
|
865
|
+
"""Create from an API response dictionary.
|
|
866
|
+
|
|
867
|
+
Args:
|
|
868
|
+
data: The dictionary to convert.
|
|
869
|
+
|
|
870
|
+
Returns:
|
|
871
|
+
A new instance.
|
|
872
|
+
"""
|
|
873
|
+
return cls(
|
|
874
|
+
source_id=data["source_id"],
|
|
875
|
+
source_type=data["source_type"],
|
|
876
|
+
action=data["action"],
|
|
877
|
+
user=data.get("user"),
|
|
878
|
+
modified_fields=data.get("modified_fields"),
|
|
879
|
+
modified_values=data.get("modified_values"),
|
|
880
|
+
ip_address=data.get("ip_address"),
|
|
881
|
+
created_at=data.get("created_at"),
|
|
882
|
+
)
|
|
883
|
+
|
|
884
|
+
|
|
885
|
+
@beartype
|
|
886
|
+
@dataclass(frozen=True, kw_only=True)
|
|
887
|
+
class ATSCodePair:
|
|
888
|
+
"""Result of an ATS Codepair invite."""
|
|
889
|
+
|
|
890
|
+
title: str | None = None
|
|
891
|
+
requisition_id: str | None = None
|
|
892
|
+
candidate_id: str | None = None
|
|
893
|
+
candidate: dict[str, JSONValue] | None = None
|
|
894
|
+
send_email: bool | None = None
|
|
895
|
+
interview_metadata: dict[str, JSONValue] | None = None
|
|
896
|
+
|
|
897
|
+
@classmethod
|
|
898
|
+
def from_dict(cls, data: ATSCodePairDict) -> Self:
|
|
899
|
+
"""Create from an API response dictionary.
|
|
900
|
+
|
|
901
|
+
Args:
|
|
902
|
+
data: The dictionary to convert.
|
|
903
|
+
|
|
904
|
+
Returns:
|
|
905
|
+
A new instance.
|
|
906
|
+
"""
|
|
907
|
+
return cls(
|
|
908
|
+
title=data.get("title"),
|
|
909
|
+
requisition_id=data.get("requisition_id"),
|
|
910
|
+
candidate_id=data.get("candidate_id"),
|
|
911
|
+
candidate=data.get("candidate"),
|
|
912
|
+
send_email=data.get("send_email"),
|
|
913
|
+
interview_metadata=data.get("interview_metadata"),
|
|
914
|
+
)
|
|
915
|
+
|
|
916
|
+
|
|
917
|
+
@beartype
|
|
918
|
+
@dataclass(frozen=True, kw_only=True)
|
|
919
|
+
class ATSCodeScreen:
|
|
920
|
+
"""Result of an ATS CodeScreen invite."""
|
|
921
|
+
|
|
922
|
+
test_id: str | None = None
|
|
923
|
+
requisition_id: str | None = None
|
|
924
|
+
candidate_id: str | None = None
|
|
925
|
+
email: str | None = None
|
|
926
|
+
test_result_url: str | None = None
|
|
927
|
+
accept_result_updates: bool | None = None
|
|
928
|
+
|
|
929
|
+
@classmethod
|
|
930
|
+
def from_dict(cls, data: ATSCodeScreenDict) -> Self:
|
|
931
|
+
"""Create from an API response dictionary.
|
|
932
|
+
|
|
933
|
+
Args:
|
|
934
|
+
data: The dictionary to convert.
|
|
935
|
+
|
|
936
|
+
Returns:
|
|
937
|
+
A new instance.
|
|
938
|
+
"""
|
|
939
|
+
return cls(
|
|
940
|
+
test_id=data.get("test_id"),
|
|
941
|
+
requisition_id=data.get("requisition_id"),
|
|
942
|
+
candidate_id=data.get("candidate_id"),
|
|
943
|
+
email=data.get("email"),
|
|
944
|
+
test_result_url=data.get("test_result_url"),
|
|
945
|
+
accept_result_updates=data.get(
|
|
946
|
+
"accept_result_updates",
|
|
947
|
+
),
|
|
948
|
+
)
|
|
949
|
+
|
|
950
|
+
|
|
951
|
+
@beartype
|
|
952
|
+
@dataclass(frozen=True, kw_only=True)
|
|
953
|
+
class SCIMUser:
|
|
954
|
+
"""A SCIM v2 user."""
|
|
955
|
+
|
|
956
|
+
id: str
|
|
957
|
+
user_name: str
|
|
958
|
+
name: dict[str, JSONValue] | None = None
|
|
959
|
+
active: bool | None = None
|
|
960
|
+
role: str | None = None
|
|
961
|
+
team_admin: bool | None = None
|
|
962
|
+
company_admin: bool | None = None
|
|
963
|
+
emails: list[dict[str, JSONValue]] | None = None
|
|
964
|
+
schemas: list[str] | None = None
|
|
965
|
+
|
|
966
|
+
@classmethod
|
|
967
|
+
def from_dict(cls, data: SCIMUserDict) -> Self:
|
|
968
|
+
"""Create from an API response dictionary.
|
|
969
|
+
|
|
970
|
+
Args:
|
|
971
|
+
data: The dictionary to convert.
|
|
972
|
+
|
|
973
|
+
Returns:
|
|
974
|
+
A new instance.
|
|
975
|
+
"""
|
|
976
|
+
return cls(
|
|
977
|
+
id=data["id"],
|
|
978
|
+
user_name=data["userName"],
|
|
979
|
+
name=data.get("name"),
|
|
980
|
+
active=data.get("active"),
|
|
981
|
+
role=data.get("role"),
|
|
982
|
+
team_admin=data.get("team_admin"),
|
|
983
|
+
company_admin=data.get("company_admin"),
|
|
984
|
+
emails=data.get("emails"),
|
|
985
|
+
schemas=data.get("schemas"),
|
|
986
|
+
)
|
|
987
|
+
|
|
988
|
+
|
|
989
|
+
@beartype
|
|
990
|
+
@dataclass(frozen=True, kw_only=True)
|
|
991
|
+
class SCIMTeam:
|
|
992
|
+
"""A SCIM v2 team."""
|
|
993
|
+
|
|
994
|
+
id: str
|
|
995
|
+
display_name: str | None = None
|
|
996
|
+
schemas: list[str] | None = None
|
|
997
|
+
|
|
998
|
+
@classmethod
|
|
999
|
+
def from_dict(cls, data: SCIMTeamDict) -> Self:
|
|
1000
|
+
"""Create from an API response dictionary.
|
|
1001
|
+
|
|
1002
|
+
Args:
|
|
1003
|
+
data: The dictionary to convert.
|
|
1004
|
+
|
|
1005
|
+
Returns:
|
|
1006
|
+
A new instance.
|
|
1007
|
+
"""
|
|
1008
|
+
return cls(
|
|
1009
|
+
id=data["id"],
|
|
1010
|
+
display_name=data.get("displayName") or data.get("diplayName"),
|
|
1011
|
+
schemas=data.get("schemas"),
|
|
1012
|
+
)
|