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/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
+ )