Coverage for cc_modules/cc_dataclasses.py: 62%

1"""

2 camcops_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

30 from dataclasses import dataclass

31 from typing import Dict, TYPE_CHECKING

32

33 if 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

44 class 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 )