paul@165 | 1 | #!/usr/bin/env python |
paul@165 | 2 | |
paul@165 | 3 | """ |
paul@165 | 4 | Metadata for document conversion. |
paul@165 | 5 | |
paul@333 | 6 | Copyright (C) 2018, 2019, 2021, 2023 Paul Boddie <paul@boddie.org.uk> |
paul@165 | 7 | |
paul@165 | 8 | This program is free software; you can redistribute it and/or modify it under |
paul@165 | 9 | the terms of the GNU General Public License as published by the Free Software |
paul@165 | 10 | Foundation; either version 3 of the License, or (at your option) any later |
paul@165 | 11 | version. |
paul@165 | 12 | |
paul@165 | 13 | This program is distributed in the hope that it will be useful, but WITHOUT |
paul@165 | 14 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
paul@165 | 15 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
paul@165 | 16 | details. |
paul@165 | 17 | |
paul@165 | 18 | You should have received a copy of the GNU General Public License along with |
paul@165 | 19 | this program. If not, see <http://www.gnu.org/licenses/>. |
paul@165 | 20 | """ |
paul@165 | 21 | |
paul@165 | 22 | from moinformat.input import get_input |
paul@165 | 23 | from moinformat.links import get_linker |
paul@165 | 24 | from moinformat.output import get_output |
paul@165 | 25 | from moinformat.parsers import get_parser, parsers |
paul@165 | 26 | from moinformat.serialisers import get_serialiser, serialisers |
paul@165 | 27 | from moinformat.themes import get_theme |
paul@347 | 28 | from moinformat.translators import get_translator, translators |
paul@165 | 29 | |
paul@165 | 30 | class Metadata: |
paul@165 | 31 | |
paul@165 | 32 | "Metadata employed in the document conversion process." |
paul@165 | 33 | |
paul@165 | 34 | defaults = { |
paul@253 | 35 | "attachments" : "attachments", |
paul@165 | 36 | "input_format" : "moin", |
paul@165 | 37 | "output_context" : "standalone", |
paul@165 | 38 | "output_format" : "moin", |
paul@253 | 39 | "root_pagename" : "FrontPage", |
paul@165 | 40 | } |
paul@165 | 41 | |
paul@165 | 42 | default_effects = { |
paul@165 | 43 | "output_format" : "link_format", |
paul@165 | 44 | } |
paul@165 | 45 | |
paul@165 | 46 | effects = { |
paul@333 | 47 | "input_context" : ["input"], |
paul@347 | 48 | "input_format" : ["parser", "serialiser", "translator"], |
paul@333 | 49 | "input_separator" : ["input"], |
paul@333 | 50 | "link_format" : ["linker"], |
paul@333 | 51 | "output_context" : ["output"], |
paul@347 | 52 | "output_format" : ["serialiser", "translator"], |
paul@333 | 53 | "theme_name" : ["theme"], |
paul@165 | 54 | } |
paul@165 | 55 | |
paul@165 | 56 | def __init__(self, parameters=None): |
paul@165 | 57 | |
paul@165 | 58 | "Initialise the metadata collection using the 'parameters'." |
paul@165 | 59 | |
paul@165 | 60 | self.parameters = parameters or {} |
paul@165 | 61 | |
paul@165 | 62 | def __repr__(self): |
paul@165 | 63 | return "Metadata(%r)" % self.parameters |
paul@165 | 64 | |
paul@165 | 65 | def copy(self): |
paul@165 | 66 | |
paul@165 | 67 | "Return a copy of this instance." |
paul@165 | 68 | |
paul@165 | 69 | parameters = {} |
paul@165 | 70 | parameters.update(self.parameters) |
paul@165 | 71 | return self.__class__(parameters) |
paul@165 | 72 | |
paul@165 | 73 | def get(self, name, default=None): |
paul@165 | 74 | |
paul@165 | 75 | """ |
paul@165 | 76 | Return the setting for 'name', returning 'default' if 'name' is not |
paul@165 | 77 | set. If 'default' is None or omitted and a default is present in the |
paul@165 | 78 | defaults registry, this is returned if no setting is defined. |
paul@165 | 79 | """ |
paul@165 | 80 | |
paul@165 | 81 | value = self.parameters.get(name, default) |
paul@165 | 82 | if value is None: |
paul@165 | 83 | return self.defaults.get(name, default) |
paul@165 | 84 | else: |
paul@165 | 85 | return value |
paul@165 | 86 | |
paul@165 | 87 | def has_key(self, name): |
paul@165 | 88 | return self.parameters.has_key(name) |
paul@165 | 89 | |
paul@165 | 90 | def set(self, name, value): |
paul@165 | 91 | |
paul@165 | 92 | "Set 'name' as 'value' in the metadata." |
paul@165 | 93 | |
paul@165 | 94 | self.parameters[name] = value |
paul@165 | 95 | |
paul@333 | 96 | # Invalidate any affected settings. |
paul@165 | 97 | |
paul@165 | 98 | affected = self.effects.get(name) |
paul@165 | 99 | |
paul@333 | 100 | if affected: |
paul@333 | 101 | for affected_name in affected: |
paul@333 | 102 | if self.has_key(affected_name): |
paul@333 | 103 | del self.parameters[affected_name] |
paul@165 | 104 | |
paul@165 | 105 | # Set any default values. |
paul@165 | 106 | |
paul@165 | 107 | affected = self.default_effects.get(name) |
paul@165 | 108 | |
paul@165 | 109 | if affected and not self.get(affected): |
paul@165 | 110 | self.set(affected, value) |
paul@165 | 111 | |
paul@333 | 112 | def get_update(self, name, value=None): |
paul@165 | 113 | |
paul@165 | 114 | """ |
paul@333 | 115 | Obtain the 'name' setting, this being overwritten by 'value' if |
paul@333 | 116 | specified. Return the updated setting. |
paul@165 | 117 | """ |
paul@165 | 118 | |
paul@333 | 119 | # Overwrite any existing setting. |
paul@165 | 120 | |
paul@333 | 121 | if value: |
paul@333 | 122 | self.set(name, value) |
paul@333 | 123 | return value |
paul@333 | 124 | else: |
paul@333 | 125 | return self.get(name) |
paul@333 | 126 | |
paul@333 | 127 | def make_object(self, name, cls): |
paul@165 | 128 | |
paul@333 | 129 | """ |
paul@333 | 130 | Make an object to be stored in the setting 'name', using 'cls' as the |
paul@333 | 131 | object class. |
paul@333 | 132 | """ |
paul@165 | 133 | |
paul@333 | 134 | # Return any existing, preserved object. Since updates to various |
paul@333 | 135 | # properties will discard objects, any preserved object should still be |
paul@333 | 136 | # applicable. |
paul@165 | 137 | |
paul@333 | 138 | obj = self.get(name) |
paul@333 | 139 | if obj: |
paul@333 | 140 | return obj |
paul@165 | 141 | |
paul@333 | 142 | # Without any object class, return None. |
paul@165 | 143 | |
paul@165 | 144 | if not cls: |
paul@165 | 145 | self.set(name, None) |
paul@165 | 146 | return None |
paul@165 | 147 | |
paul@333 | 148 | # Instantiate the class and record the object. |
paul@165 | 149 | |
paul@165 | 150 | obj = cls(self) |
paul@165 | 151 | self.set(name, obj) |
paul@165 | 152 | return obj |
paul@165 | 153 | |
paul@165 | 154 | def get_input(self, name=None): |
paul@165 | 155 | |
paul@165 | 156 | """ |
paul@165 | 157 | Make an input context using any given 'name' or otherwise using the |
paul@165 | 158 | "input_context" setting which will be replaced by any given 'name'. |
paul@165 | 159 | """ |
paul@165 | 160 | |
paul@333 | 161 | cls = get_input(self.get_update("input_context", name)) |
paul@333 | 162 | |
paul@333 | 163 | return self.make_object("input", cls) |
paul@165 | 164 | |
paul@165 | 165 | def get_linker(self, name=None): |
paul@165 | 166 | |
paul@165 | 167 | """ |
paul@165 | 168 | Make a linker using any given 'name' or otherwise using the |
paul@165 | 169 | "link_format" setting which will be replaced by any given 'name'. |
paul@165 | 170 | """ |
paul@165 | 171 | |
paul@333 | 172 | cls = get_linker(self.get_update("link_format", name)) |
paul@333 | 173 | |
paul@333 | 174 | return self.make_object("linker", cls) |
paul@165 | 175 | |
paul@165 | 176 | def get_output(self, name=None): |
paul@165 | 177 | |
paul@165 | 178 | """ |
paul@165 | 179 | Make an output context using any given 'name' or otherwise using the |
paul@165 | 180 | "output_context" setting which will be replaced by any given 'name'. |
paul@165 | 181 | """ |
paul@165 | 182 | |
paul@333 | 183 | cls = get_output(self.get_update("output_context", name)) |
paul@333 | 184 | |
paul@333 | 185 | return self.make_object("output", cls) |
paul@165 | 186 | |
paul@165 | 187 | def get_parser(self, name=None): |
paul@165 | 188 | |
paul@165 | 189 | """ |
paul@165 | 190 | Make a parser using any given 'name' or otherwise using the |
paul@165 | 191 | "input_format" setting which will be replaced by any given 'name'. |
paul@165 | 192 | """ |
paul@165 | 193 | |
paul@333 | 194 | cls = get_parser(self.get_update("input_format", name)) |
paul@333 | 195 | |
paul@333 | 196 | parser = self.make_object("parser", cls) |
paul@165 | 197 | parser.parsers = parsers |
paul@165 | 198 | return parser |
paul@165 | 199 | |
paul@165 | 200 | def get_serialiser(self, name=None): |
paul@165 | 201 | |
paul@165 | 202 | """ |
paul@165 | 203 | Make a serialiser using any given 'name' or otherwise using the |
paul@165 | 204 | "output_format" setting which will be replaced by any given 'name'. |
paul@165 | 205 | """ |
paul@165 | 206 | |
paul@333 | 207 | cls = get_serialiser(self.get_update("output_format", name), |
paul@333 | 208 | self.get("input_format")) |
paul@333 | 209 | |
paul@333 | 210 | serialiser = self.make_object("serialiser", cls) |
paul@165 | 211 | serialiser.serialisers = serialisers |
paul@165 | 212 | return serialiser |
paul@165 | 213 | |
paul@165 | 214 | def get_theme(self, name=None): |
paul@165 | 215 | |
paul@165 | 216 | """ |
paul@165 | 217 | Make a theme using any given 'name' or otherwise using the "theme_name" |
paul@165 | 218 | setting which will be replaced by any given 'name'. |
paul@165 | 219 | """ |
paul@165 | 220 | |
paul@333 | 221 | cls = get_theme(self.get_update("theme_name", name)) |
paul@333 | 222 | |
paul@333 | 223 | return self.make_object("theme", cls) |
paul@165 | 224 | |
paul@347 | 225 | def get_translator(self, name=None): |
paul@347 | 226 | |
paul@347 | 227 | """ |
paul@347 | 228 | Make a translator using any given 'name' or otherwise using the |
paul@347 | 229 | "output_format" setting which will be replaced by any given 'name'. |
paul@347 | 230 | """ |
paul@347 | 231 | |
paul@347 | 232 | cls = get_translator(self.get_update("output_format", name), |
paul@347 | 233 | self.get("input_format")) |
paul@347 | 234 | |
paul@347 | 235 | translator = self.make_object("translator", cls) |
paul@347 | 236 | translator.translators = translators |
paul@347 | 237 | return translator |
paul@347 | 238 | |
paul@165 | 239 | # vim: tabstop=4 expandtab shiftwidth=4 |