Coverage for cc_modules/cc_dataclasses.py: 62%

32 statements  

« prev     ^ index     » next       coverage.py v7.9.2, created at 2025-07-15 14:23 +0100

1""" 

2camcops_server/cc_modules/cc_dataclasses.py 

3 

4=============================================================================== 

5 

6 Copyright (C) 2012, University of Cambridge, Department of Psychiatry. 

7 Created by Rudolf Cardinal (rnc1001@cam.ac.uk). 

8 

9 This file is part of CamCOPS. 

10 

11 CamCOPS is free software: you can redistribute it and/or modify 

12 it under the terms of the GNU General Public License as published by 

13 the Free Software Foundation, either version 3 of the License, or 

14 (at your option) any later version. 

15 

16 CamCOPS is distributed in the hope that it will be useful, 

17 but WITHOUT ANY WARRANTY; without even the implied warranty of 

18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

19 GNU General Public License for more details. 

20 

21 You should have received a copy of the GNU General Public License 

22 along with CamCOPS. If not, see <https://www.gnu.org/licenses/>. 

23 

24=============================================================================== 

25 

26**Dataclasses.** 

27 

28""" 

29 

30from dataclasses import dataclass 

31from typing import Dict, TYPE_CHECKING 

32 

33if TYPE_CHECKING: 

34 from sqlalchemy.sql.schema import Column 

35 from camcops_server.cc_modules.cc_summaryelement import SummaryElement 

36 

37 

38# ============================================================================= 

39# SummarySchemaInfo 

40# ============================================================================= 

41 

42 

43@dataclass(eq=True, frozen=True, order=True) # hashable, sortable 

44class SummarySchemaInfo: 

45 """ 

46 Information to be given to the user about the schema for spreadsheet-style 

47 downloads, including database and summary columns. 

48 """ 

49 

50 # Summary schema values: 

51 SSV_DB = "database" 

52 SSV_SUMMARY = "summary" 

53 VALID_SOURCES = {SSV_DB, SSV_SUMMARY} 

54 

55 table_name: str 

56 source: str 

57 column_name: str 

58 data_type: str 

59 comment: str 

60 

61 def __post_init__(self) -> None: 

62 assert ( 

63 self.source in self.VALID_SOURCES 

64 ), f"Bad source: {self.source!r}" 

65 

66 @property 

67 def as_dict(self) -> Dict[str, str]: 

68 """ 

69 Used to create spreadsheet rows. Maps spreadsheet headings to values. 

70 """ 

71 return { 

72 "table_name": self.table_name, 

73 "source": self.source, 

74 "column_name": self.column_name, 

75 "data_type": self.data_type, 

76 "comment": self.comment, 

77 } 

78 

79 @classmethod 

80 def from_column( 

81 cls, 

82 column: "Column", 

83 table_name: str = "", 

84 source: str = "", 

85 column_name_prefix: str = "", 

86 ) -> "SummarySchemaInfo": 

87 """ 

88 Create from an SQLAlchemy column. 

89 """ 

90 if not table_name: 

91 if column.table is not None: 

92 table_name = column.table.name 

93 else: 

94 raise ValueError( 

95 f"table_name not specified and column not " 

96 f"attached to a table: {column!r}" 

97 ) 

98 source = source or cls.SSV_DB 

99 return cls( 

100 table_name=table_name, 

101 source=source, 

102 column_name=column_name_prefix + column.name, 

103 data_type=str(column.type), 

104 comment=column.comment, 

105 ) 

106 

107 @classmethod 

108 def from_summary_element( 

109 cls, 

110 table_name: str, 

111 element: "SummaryElement", 

112 source: str = "", 

113 column_name_prefix: str = "", 

114 ) -> "SummarySchemaInfo": 

115 """ 

116 Create from a 

117 :class:`camcops_server.cc_modules.cc_summaryelement.SummarySchemaInfo`. 

118 """ 

119 source = source or cls.SSV_SUMMARY 

120 return cls( 

121 table_name=table_name, 

122 source=source, 

123 column_name=column_name_prefix + element.name, 

124 data_type=str(element.coltype), 

125 comment=element.decorated_comment, 

126 )