error.py (8327B)
1 from plint import common 2 3 4 class ReportableError: 5 6 def report(self, pattern): 7 raise NotImplementedError 8 9 10 class ErrorCollection(ReportableError): 11 keys = {'hiatus': 'H', 'ambiguous': 'A', 'illegal': 'I'} 12 13 @property 14 def prefix(self): 15 return "stdin:%d: " % self.line_no 16 17 def __init__(self, line_no, line, pattern, verse, errors=None): 18 self.line_no = line_no 19 self.line = line 20 self.errors = errors or [] 21 self.pattern = pattern 22 self.verse = verse 23 24 def isEmpty(self): 25 return len(self.errors) == 0 26 27 def say(self, l, short): 28 return l if short else self.prefix + l 29 30 def align(self, fmt="text"): 31 return self.verse.align(fmt=fmt) 32 33 def lines(self, short=False, fmt="text"): 34 result = [] 35 if self.verse.possible is not None: 36 result.append([self.say(x, short) for x in self.align(fmt=fmt)]) 37 for e in self.errors: 38 result.append([self.say(e.report(self.pattern, fmt=fmt), short)]) 39 return result 40 41 def report(self, short=False, fmt="text"): 42 if fmt == "text": 43 return '\n'.join(sum(self.lines(short, fmt=fmt), [])) 44 elif fmt == "json": 45 return { 46 'line': self.line, 47 'line_no': self.line_no, 48 'possible_parsings': self.align(fmt=fmt), 49 'errors': [ 50 e.report(self.pattern, fmt=fmt) 51 for e in self.errors] 52 } 53 else: 54 raise ValueError("bad format") 55 56 57 class ErrorBadElement(ReportableError): 58 59 def __init__(self): 60 self.message = None 61 self.key = None 62 self.report_key = None 63 64 def report(self, pattern, fmt="text"): 65 if fmt == "text": 66 return (self.message 67 + _(" (see '%s' above)")) % ErrorCollection.keys[self.key] 68 elif fmt == "json": 69 return {'error': self.report_key, 70 'error_kind': "local_error_collection"} 71 else: 72 raise ValueError("bad format") 73 74 75 class ErrorBadCharacters(ErrorBadElement): 76 77 def __init__(self): 78 super().__init__() 79 self.message = _("Illegal characters") 80 self.key = "illegal" 81 self.report_key = "illegal_characters" 82 83 84 class ErrorForbiddenPattern(ErrorBadElement): 85 86 def __init__(self): 87 super().__init__() 88 self.message = _("Illegal ambiguous pattern") 89 self.key = "ambiguous" 90 self.report_key = "ambiguous_patterns" 91 92 93 class ErrorHiatus(ErrorBadElement): 94 95 def __init__(self): 96 super().__init__() 97 self.message = _("Illegal hiatus") 98 self.key = "hiatus" 99 self.report_key = "hiatus" 100 101 102 class ErrorBadRhyme(ReportableError): 103 104 def __init__(self, expected, inferred, old_phon=None): 105 self.expected = expected 106 self.inferred = inferred 107 self.old_phon = old_phon 108 self.kind_human = None 109 self.kind = None 110 111 def get_id(self, pattern): 112 raise NotImplementedError 113 114 def fmt(self, l, fmt="text"): 115 raise NotImplementedError 116 117 def report(self, pattern, fmt="text"): 118 if fmt == "text": 119 return (_("%s for type %s (expected %s, inferred %s)") 120 % (self.kind_human, self.get_id(pattern), 121 self.fmt(self.expected, fmt=fmt), 122 self.fmt(self.inferred, fmt=fmt))) 123 elif fmt == "json": 124 return { 125 'error': self.kind, 'error_kind': "rhyme_error", 126 'pattern_rhyme_type': self.get_id(pattern), 127 'expected': self.fmt(self.expected, fmt=fmt), 128 'inferred': self.fmt(self.inferred, fmt=fmt)} 129 else: 130 raise ValueError("bad format") 131 132 133 class ErrorBadRhymeGenre(ErrorBadRhyme): 134 135 def __init__(self, expected, inferred, old_phon=None): 136 super().__init__(expected, inferred, old_phon) 137 self.kind_human = _("Bad rhyme genre") 138 self.kind = "rhyme_genre" 139 140 def fmt(self, l, fmt="text"): 141 if fmt == "text": 142 result = _(' or ').join(sorted(list(l))) 143 if result == '': 144 result = "?" 145 return "\"" + result + "\"" 146 elif fmt == "json": 147 return sorted(list(l)) 148 else: 149 raise ValueError("bad format") 150 151 def get_id(self, pattern): 152 return pattern.feminine_id 153 154 155 class ErrorBadRhymeObject(ErrorBadRhyme): 156 157 def fmt(self, l): 158 raise NotImplementedError 159 160 def get_id(self, pattern): 161 return pattern.my_id 162 163 164 class ErrorBadRhymeSound(ErrorBadRhymeObject): 165 166 def __init__(self, expected, inferred, old_phon=None): 167 super().__init__(expected, inferred, old_phon) 168 self.kind_human = _("Bad rhyme sound") 169 self.kind = "rhyme_sound" 170 171 def fmt(self, l, fmt="text"): 172 if fmt == "text": 173 return ('/'.join("\"" + common.to_xsampa(x) + "\"" 174 for x in sorted(list(l.sufficient_phon())))) 175 elif fmt == "json": 176 return (sorted(common.to_xsampa(x) 177 for x in list(l.sufficient_phon()))) 178 else: 179 raise ValueError("bad format") 180 181 182 class ErrorBadRhymeEye(ErrorBadRhymeObject): 183 184 def __init__(self, expected, inferred, old_phon=None): 185 super().__init__(expected, inferred, old_phon) 186 self.kind_human = _("Bad rhyme ending") 187 self.kind = "rhyme_ending" 188 189 def fmt(self, l, fmt="text"): 190 if fmt == "text": 191 return "\"-" + l.sufficient_eye(self.old_phon) + "\"" 192 elif fmt == "json": 193 return (l.sufficient_eye(self.old_phon)) 194 else: 195 raise ValueError("bad format") 196 197 198 class ErrorBadMetric(ReportableError): 199 200 def report(self, pattern, fmt="text"): 201 if fmt == "text": 202 plural_hemistiche = '' if len(pattern.hemistiches) == 1 else 's' 203 plural_syllable = '' if pattern.length == 1 else 's' 204 if len(pattern.hemistiches) == 0: 205 hemistiche_string = "" 206 else: 207 hemistiche_positions = (','.join(str(a) 208 for a in pattern.hemistiches)) 209 hemistiche_string = ((_(" with hemistiche%s at ") 210 % plural_hemistiche) + hemistiche_positions) 211 return (_("Illegal metric: expected %d syllable%s%s") % 212 (pattern.length, plural_syllable, hemistiche_string)) 213 elif fmt == "json": 214 return { 215 'error': "metric", 'error_kind': "metric_error", 216 'expected_syllables': pattern.length, 217 'expected_hemistiches': pattern.hemistiches 218 } 219 else: 220 raise ValueError("bad format") 221 222 223 class ErrorMultipleWordOccurrence(ReportableError): 224 225 def __init__(self, word, occurrences): 226 self.word = word 227 self.occurrences = occurrences 228 229 def report(self, pattern, fmt="text"): 230 if fmt == "text": 231 return (_("Too many occurrences of word \"%s\" for rhyme %s") 232 % (self.word, pattern.my_id)) 233 elif fmt == "json": 234 return { 235 'error': "rhyme_occurrences", 'error_kind': "rhyme_error", 236 'pattern_rhyme_type': pattern.my_id, 237 'word': self.word 238 } 239 else: 240 raise ValueError("bad format") 241 242 243 class ErrorIncompleteTemplate(ReportableError): 244 245 def report(self, pattern, fmt="text"): 246 if fmt == "text": 247 return _("Poem is not complete") 248 elif fmt == "json": 249 return { 250 'error': "incomplete_poem", 251 'error_kind': "global_error" 252 } 253 else: 254 raise ValueError("bad format") 255 256 257 258 class ErrorOverflowedTemplate(ReportableError): 259 260 def report(self, pattern, fmt="text"): 261 if fmt == "text": 262 return _("Verse is beyond end of poem") 263 elif fmt == "json": 264 return { 265 'error': "verse_beyond_end_of_poem", 266 'error_kind': "global_error" 267 } 268 else: 269 raise ValueError("bad format") 270 271 272 class TemplateLoadError(BaseException): 273 274 def __init__(self, msg): 275 self.msg = msg