Coverage for src / competitive_verifier / documents / render_data.py: 96%

49 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-03-05 16:00 +0000

1import datetime 

2import enum 

3from collections.abc import Sequence 

4from typing import Annotated, Any 

5 

6from pydantic import BaseModel, ConfigDict, PlainSerializer, model_validator 

7from pydantic.alias_generators import to_camel 

8 

9from competitive_verifier.models import ForcePosixPath, SortedPathList, TestcaseResult 

10 

11 

12class StatusIcon(str, enum.Enum): 

13 @property 

14 def is_failed(self) -> bool: 

15 return not self.is_success 

16 

17 @property 

18 def is_success(self) -> bool: 

19 return self in ( 

20 self.LIBRARY_ALL_AC, 

21 self.LIBRARY_PARTIAL_AC, 

22 self.LIBRARY_NO_TESTS, 

23 self.TEST_ACCEPTED, 

24 self.TEST_WAITING_JUDGE, 

25 ) 

26 

27 @property 

28 def is_test(self) -> bool: 

29 return not self.is_library 

30 

31 @property 

32 def is_library(self) -> bool: 

33 return self in ( 

34 self.LIBRARY_ALL_AC, 

35 self.LIBRARY_PARTIAL_AC, 

36 self.LIBRARY_SOME_WA, 

37 self.LIBRARY_ALL_WA, 

38 self.LIBRARY_NO_TESTS, 

39 ) 

40 

41 LIBRARY_ALL_AC = "LIBRARY_ALL_AC" 

42 LIBRARY_PARTIAL_AC = "LIBRARY_PARTIAL_AC" 

43 LIBRARY_SOME_WA = "LIBRARY_SOME_WA" 

44 LIBRARY_ALL_WA = "LIBRARY_ALL_WA" 

45 LIBRARY_NO_TESTS = "LIBRARY_NO_TESTS" 

46 TEST_ACCEPTED = "TEST_ACCEPTED" 

47 TEST_WRONG_ANSWER = "TEST_WRONG_ANSWER" 

48 TEST_WAITING_JUDGE = "TEST_WAITING_JUDGE" 

49 

50 

51class RenderBaseModel(BaseModel): 

52 model_config = ConfigDict( 

53 alias_generator=to_camel, 

54 populate_by_name=True, 

55 extra="allow", 

56 ) 

57 

58 

59class RenderLink(RenderBaseModel): 

60 path: ForcePosixPath 

61 filename: str 

62 icon: StatusIcon 

63 title: str | None = None 

64 

65 @model_validator(mode="after") 

66 def validate_title(self: "RenderLink") -> "RenderLink": 

67 if self.path.as_posix() == self.title: 67 ↛ 68line 67 didn't jump to line 68 because the condition on line 67 was never true

68 self.title = None 

69 return self 

70 

71 

72class Dependency(RenderBaseModel): 

73 type: str 

74 files: list[RenderLink] 

75 

76 

77class EmbeddedCode(RenderBaseModel): 

78 name: str 

79 code: str 

80 

81 

82class EnvTestcaseResult(RenderBaseModel, TestcaseResult): 

83 environment: str | None 

84 

85 

86class CategorizedIndex(RenderBaseModel): 

87 name: str 

88 pages: list[RenderLink] 

89 

90 

91class IndexFiles(RenderBaseModel): 

92 type: str 

93 categories: list[CategorizedIndex] 

94 

95 

96class PageRenderData(RenderBaseModel): 

97 path: ForcePosixPath 

98 path_extension: str 

99 title: str | None 

100 embedded: list[EmbeddedCode] 

101 

102 timestamp: Annotated[ 

103 datetime.datetime, 

104 PlainSerializer(lambda x: str(x), return_type=str, when_used="json"), 

105 ] 

106 attributes: dict[str, Any] 

107 testcases: list[EnvTestcaseResult] | None = None 

108 

109 is_failed: bool 

110 is_verification_file: bool 

111 verification_status: StatusIcon 

112 

113 depends_on: SortedPathList 

114 required_by: SortedPathList 

115 verified_with: SortedPathList 

116 

117 document_path: ForcePosixPath | None = None 

118 dependencies: list[Dependency] 

119 

120 

121class CodePageData(PageRenderData): 

122 document_content: str | None 

123 

124 

125class MultiCodePageData(RenderBaseModel): 

126 path: ForcePosixPath 

127 verification_status: StatusIcon 

128 is_failed: bool 

129 codes: Sequence[CodePageData] 

130 dependencies: list[Dependency] 

131 

132 

133class IndexRenderData(RenderBaseModel): 

134 top: list[IndexFiles]