Source code for bibble.failure.failure_handler

  1#!/usr/bin/env python3
  2"""
  3
  4"""
  5
  6# Imports:
  7from __future__ import annotations
  8
  9# ##-- stdlib imports
 10import datetime
 11import enum
 12import functools as ftz
 13import itertools as itz
 14import logging as logmod
 15import pathlib as pl
 16import re
 17import time
 18import types
 19import weakref
 20from uuid import UUID, uuid1
 21
 22# ##-- end stdlib imports
 23
 24# ##-- 3rd party imports
 25import bibtexparser
 26import bibtexparser.model as model
 27from bibtexparser import middlewares as ms
 28from bibtexparser.middlewares.middleware import (BlockMiddleware,
 29                                                 LibraryMiddleware)
 30from jgdv import Proto
 31# ##-- end 3rd party imports
 32
 33import bibble._interface as API
 34from bibble.util.middlecore import IdenLibraryMiddleware
 35import bibble.model as bmodel
 36
 37# ##-- types
 38# isort: off
 39import abc
 40import collections.abc
 41from typing import TYPE_CHECKING, cast, assert_type, assert_never
 42from typing import Generic, NewType
 43# Protocols:
 44from typing import Protocol, runtime_checkable
 45# Typing Decorators:
 46from typing import no_type_check, final, override, overload
 47
 48if TYPE_CHECKING:
 49    from jgdv import Maybe
 50    from typing import Final
 51    from typing import ClassVar, Any, LiteralString
 52    from typing import Never, Self, Literal
 53    from typing import TypeGuard
 54    from collections.abc import Iterable, Iterator, Callable, Generator
 55    from collections.abc import Sequence, Mapping, MutableMapping, Hashable
 56
 57    type Logger = logmod.Logger
 58##--|
 59
 60# isort: on
 61# ##-- end types
 62
 63##-- logging
 64logging = logmod.getLogger(__name__)
 65##-- end logging
 66
[docs] 67class FailureLogHandler(IdenLibraryMiddleware): 68 """ Middleware to Filter failed blocks of a library, 69 either to a logger output, or to a file 70 Put at end of parse stack 71 72 Will log out where the failed blocks start by line. 73 """ 74
[docs] 75 def transform(self, library): 76 total = len(library.failed_blocks) 77 reported = [] 78 for i, block in enumerate(library.failed_blocks, start=1): 79 source_file = self._find_source_file(block, library) 80 match block: 81 case bmodel.FailedBlock(): 82 report = block.report(i=i, total=total, source_file=source_file)[0] 83 case model.ParsingFailedBlock() if source_file: 84 report = f"({i}/{total}) Bad Block: : {block.start_line} : {source_file} : {block.error}" 85 case model.ParsingFailedBlock(): 86 report = f"({i}/{total}) Bad Block: : {block.start_line} : {block.error}" 87 case x: 88 raise TypeError(type(x)) 89 ##--| 90 reported.append((report, block.error, block.raw)) 91 self._logger.warning(report) 92 else: 93 return library
94
[docs] 95 def _find_source_file(self, block, library) -> Maybe[str]: 96 match block: 97 case model.Entry(): 98 target_key = block.key 99 case _: 100 return None 101 102 match bmodel.MetaBlock.find_in(library): 103 case None: 104 return None 105 case bmodel.MetaBlock() as meta if 'sources' not in meta.data: 106 return None 107 case bmodel.MetaBlock() as meta: 108 data = meta.data 109 sources = meta.data['sources'] 110 111 for source in sources: 112 if source in data and target_key in data[source]: 113 return source 114 ##--| 115 else: 116 return None
117 118
[docs] 119class FailureWriteHandler(IdenLibraryMiddleware): 120 """ Middleware to Filter failed blocks of a library, 121 either to a logger output, or to a file 122 Put at end of parse stack 123 124 Will log out where the failed blocks start by line. 125 """ 126 127 def __init__(self, *, file:Maybe[str|pl.Path]=None, **kwargs): 128 super().__init__(**kwargs) 129 match file: 130 case str() as x: 131 self.file_target = pl.Path(x) 132 case pl.Path() as x: 133 self.file_target = x 134 case _: 135 self.file_target = None 136 137
[docs] 138 def transform(self, library): 139 total = len(library.failed_blocks) 140 reported = [] 141 for i, block in enumerate(library.failed_blocks, start=1): 142 source_file = self._find_source_file(block, library) 143 match block: 144 case bmodel.FailedBlock(): 145 report = block.report(i=i, total=total, source_file=source_file)[0] 146 case model.ParsingFailedBlock() if source_file: 147 report = f"({i}/{total}) Bad Block: : {block.start_line} : {source_file} : {block.error}" 148 case model.ParsingFailedBlock(): 149 report = f"({i}/{total}) Bad Block: : {block.start_line} : {block.error}" 150 case x: 151 raise TypeError(type(x)) 152 ##--| 153 reported.append((report, block.error, block.raw)) 154 else: 155 self.write_failures_to_file(reported) 156 return library
157
[docs] 158 def write_failures_to_file(self, reports:list) -> None: 159 match reports: 160 case []: 161 return 162 case _ if self.file_target is None: 163 return 164 case _: 165 pass 166 167 total = len(reports) 168 with self.file_target.open("w") as f: 169 for rep, err, raw in reports: 170 f.writelines(["\n\n--------------------\n", 171 rep, 172 f"\nError: {err}", 173 "\n--------------------\n", 174 raw, 175 ])
176
[docs] 177 def _find_source_file(self, block, library) -> Maybe[str]: 178 match block: 179 case model.Entry(): 180 target_key = block.key 181 case _: 182 return None 183 184 match bmodel.MetaBlock.find_in(library): 185 case None: 186 return None 187 case bmodel.MetaBlock() as meta if 'sources' not in meta.data: 188 return None 189 case bmodel.MetaBlock() as meta: 190 data = meta.data 191 sources = meta.data['sources'] 192 193 for source in sources: 194 if source in data and target_key in data[source]: 195 return source 196 ##--| 197 else: 198 return None