95.16%

62 statements  

« prev     ^ index     » next       coverage.py v7.6.8, created at 2024-11-25 15:36:16 +00:00

1"""Splice (Finnish liitos) contributions.""" 

2 

3import datetime as dti 

4import logging 

5import os 

6import pathlib 

7import shellingham # type: ignore 

8from typing import Union, no_type_check 

9 

10# [[[fill git_describe()]]] 

11__version__ = '2024.2.13+parent.g40277e46' 

12# [[[end]]] (checksum: 43d59767764b506b0675fed1fd626c3e) 

13__version_info__ = tuple( 

14 e if '-' not in e else e.split('-')[0] for part in __version__.split('+') for e in part.split('.') if e != 'parent' 

15) 

16 

17APP_ALIAS = str(pathlib.Path(__file__).parent.name) 

18APP_ENV = APP_ALIAS.upper() 

19APP_NAME = locals()['__doc__'] 

20DEBUG = bool(os.getenv(f'{APP_ENV}_DEBUG', '')) 

21VERBOSE = bool(os.getenv(f'{APP_ENV}_VERBOSE', '')) 

22QUIET = False 

23STRICT = bool(os.getenv(f'{APP_ENV}_STRICT', '')) 

24ENCODING = 'utf-8' 

25ENCODING_ERRORS_POLICY = 'ignore' 

26DEFAULT_CONFIG_NAME = f'.{APP_ALIAS}.json' 

27 

28APP_VERSION = __version__ 

29COMMA = ',' 

30DEFAULT_LF_ONLY = 'YES' 

31FILTER_CS_LIST = 'mermaid-filter' 

32FROM_FORMAT_SPEC = 'markdown' 

33LATEX_PAYLOAD_NAME = 'document.tex' 

34log = logging.getLogger() # Module level logger is sufficient 

35LOG_FOLDER = pathlib.Path('logs') 

36LOG_FILE = f'{APP_ALIAS}.log' 

37LOG_PATH = pathlib.Path(LOG_FOLDER, LOG_FILE) if LOG_FOLDER.is_dir() else pathlib.Path(LOG_FILE) 

38LOG_LEVEL = logging.INFO 

39LOG_SEPARATOR = '- ' * 80 

40 

41DEFAULT_STRUCTURE_NAME = 'structure.yml' 

42KEY_APPROVALS = 'approvals' 

43KEY_BIND = 'bind' 

44KEY_CHANGES = 'changes' 

45KEY_LAYOUT = 'layout' 

46KEY_META = 'meta' 

47KEYS_REQUIRED = (KEY_APPROVALS, KEY_BIND, KEY_CHANGES, KEY_META) 

48 

49CONTEXT: dict[str, str] = {} 

50KNOWN_APPROVALS_STRATEGIES = ('south', 'east') 

51APPROVALS_STRATEGY = os.getenv('LIITOS_APPROVALS_STRATEGY', '').lower() 

52 

53PathLike = Union[str, pathlib.Path] 

54 

55try: 

56 SHELL = shellingham.detect_shell() 

57except shellingham.ShellDetectionFailure: 

58 SHELL = ('', 'echo') 

59 

60TOOL_VERSION_COMMAND_MAP = { 

61 'etiketti': { 

62 'command': 'etiketti --version', 

63 'banner': 'Label and document the pdf file (data protection and identity)', 

64 }, 

65 'exiftool': { 

66 'command': 'exiftool -ver', 

67 'banner': 'Change and list EXIF attributes', 

68 }, 

69 'foran': { 

70 'command': 'foran version', 

71 'banner': 'Inspect local git status (or detect that there is no repository)', 

72 }, 

73 'git': { 

74 'command': 'git --version', 

75 'banner': 'Version control system (git)', 

76 }, 

77 'liitos': { 

78 'command': 'liitos version', 

79 'banner': 'Process the markdown documentation to produce PDF', 

80 }, 

81 'lualatex': { 

82 'command': 'lualatex --version', 

83 'banner': 'Process LaTeX to produce PDF', 

84 }, 

85 'mermaid': { 

86 'command': 'npm view mermaid', 

87 'banner': 'Mermaid for rendering diagrams from textual representations', 

88 }, 

89 'mermaid-filter': { 

90 'command': 'npm view mermaid-filter', 

91 'banner': 'Pandoc filter for mermaid diagrams (rasterized version for PDF)', 

92 }, 

93 'navigaattori': { 

94 'command': 'navigaattori version', 

95 'banner': 'Discover publication structural information from tree', 

96 }, 

97 'node': { 

98 'command': 'node --version', 

99 'banner': 'Node server for executing some tools', 

100 }, 

101 'npm': { 

102 'command': 'npm --version', 

103 'banner': 'Node package manager for inspecting versions of some node based tools', 

104 }, 

105 'pandoc': { 

106 'command': 'pandoc --version', 

107 'banner': 'Pandoc for transforming markdown to LaTeX', 

108 }, 

109 'pdfinfo': { 

110 'command': 'pdfinfo -v', 

111 'banner': 'Show PDF file information', 

112 }, 

113 'python': { 

114 'command': 'python -V', 

115 'banner': 'Python driving it all', 

116 }, 

117 'shell': { 

118 'command': f'{SHELL[1]} --version', 

119 'banner': 'The shell under which this process executes', 

120 }, 

121 'svgexport': { 

122 'command': 'npm view svgexport', 

123 'banner': 'Export SVG to PNG (rasterized version for inclusion in PDF)', 

124 }, 

125 'taksonomia': { 

126 'command': 'taksonomia --version', 

127 'banner': 'Assess and document the inventory of folders and files', 

128 }, 

129} 

130 

131ToolKey = str 

132 

133TS_FORMAT_LOG = '%Y-%m-%dT%H:%M:%S' 

134TS_FORMAT_PAYLOADS = '%Y-%m-%d %H:%M:%S.%f UTC' 

135 

136__all__: list[str] = [ 

137 'APP_ALIAS', 

138 'APP_ENV', 

139 'APP_VERSION', 

140 'APPROVALS_STRATEGY', 

141 'DEFAULT_STRUCTURE_NAME', 

142 'ENCODING', 

143 'CONTEXT', 

144 'FILTER_CS_LIST', 

145 'FROM_FORMAT_SPEC', 

146 'KEY_APPROVALS', 

147 'KEY_BIND', 

148 'KEY_CHANGES', 

149 'KEY_LAYOUT', 

150 'KEY_META', 

151 'KEYS_REQUIRED', 

152 'KNOWN_APPROVALS_STRATEGIES', 

153 'LATEX_PAYLOAD_NAME', 

154 'LOG_SEPARATOR', 

155 'PathLike', 

156 'TOOL_VERSION_COMMAND_MAP', 

157 'ToolKey', 

158 'TS_FORMAT_PAYLOADS', 

159 'log', 

160 'parse_csl', 

161] 

162 

163 

164def parse_csl(csl: str) -> list[str]: 

165 """DRY.""" 

166 return [fmt.strip() for fmt in csl.split(COMMA) if fmt.strip()] 

167 

168 

169@no_type_check 

170def formatTime_RFC3339(self, record, datefmt=None): # noqa 

171 """HACK A DID ACK we could inject .astimezone() to localize ...""" 

172 return dti.datetime.fromtimestamp(record.created, dti.timezone.utc).isoformat() # pragma: no cover 

173 

174 

175@no_type_check 

176def init_logger(name=None, level=None): 

177 """Initialize module level logger""" 

178 global log # pylint: disable=global-statement 

179 

180 log_format = { 

181 'format': '%(asctime)s %(levelname)s [%(name)s]: %(message)s', 

182 'datefmt': TS_FORMAT_LOG, 

183 # 'filename': LOG_PATH, 

184 'level': LOG_LEVEL if level is None else level, 

185 } 

186 logging.Formatter.formatTime = formatTime_RFC3339 

187 logging.basicConfig(**log_format) 

188 log = logging.getLogger(APP_ENV if name is None else name) 

189 log.propagate = True 

190 

191 

192init_logger(name=APP_ENV, level=logging.DEBUG if DEBUG else None)