Coverage for liitos/__init__.py: 97.06%
62 statements
« prev ^ index » next coverage.py v7.6.0, created at 2024-07-16 00:43:25 +00:00
« prev ^ index » next coverage.py v7.6.0, created at 2024-07-16 00:43:25 +00:00
1"""Splice (Finnish liitos) contributions."""
3import datetime as dti
4import logging
5import os
6import pathlib
7import shellingham # type: ignore
8from typing import Union, no_type_check
10# [[[fill git_describe()]]]
11__version__ = '2024.7.15+parent.g7d1232bd'
12# [[[end]]] (checksum: ff5013c1c375e94e54b257e64df63d30)
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)
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'
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
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)
49CONTEXT: dict[str, str] = {}
50KNOWN_APPROVALS_STRATEGIES = ('south', 'east')
51APPROVALS_STRATEGY = os.getenv('LIITOS_APPROVALS_STRATEGY', '').lower()
53PathLike = Union[str, pathlib.Path]
55try:
56 SHELL = shellingham.detect_shell()
57except shellingham.ShellDetectionFailure:
58 SHELL = ('', 'echo')
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}
131ToolKey = str
133TS_FORMAT_LOG = '%Y-%m-%dT%H:%M:%S'
134TS_FORMAT_PAYLOADS = '%Y-%m-%d %H:%M:%S.%f UTC'
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]
164def parse_csl(csl: str) -> list[str]:
165 """DRY."""
166 return [fmt.strip() for fmt in csl.split(COMMA) if fmt.strip()]
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
175@no_type_check
176def init_logger(name=None, level=None):
177 """Initialize module level logger"""
178 global log # pylint: disable=global-statement
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
192init_logger(name=APP_ENV, level=logging.DEBUG if DEBUG else None)