Source code for bibble.files.path_writer

  1#!/usr/bin/env python3
  2"""
  3
  4See EOF for license/metadata/notes as applicable
  5"""
  6
  7# Imports:
  8from __future__ import annotations
  9
 10# ##-- stdlib imports
 11import datetime
 12import enum
 13import functools as ftz
 14import itertools as itz
 15import logging as logmod
 16import pathlib as pl
 17import re
 18import time
 19import types
 20import weakref
 21from uuid import UUID, uuid1
 22
 23# ##-- end stdlib imports
 24
 25# ##-- 3rd party imports
 26from jgdv import Proto, Mixin
 27import bibtexparser
 28import bibtexparser.model as model
 29from bibtexparser.library import Library
 30from bibtexparser import middlewares as ms
 31from bibtexparser.middlewares.middleware import (BlockMiddleware, LibraryMiddleware)
 32
 33# ##-- end 3rd party imports
 34
 35# ##-- 1st party imports
 36import bibble._interface as API
 37from bibble.util.mixins import ErrorRaiser_m, FieldMatcher_m
 38from bibble.util.middlecore import IdenBlockMiddleware
 39from bibble.model import MetaBlock
 40
 41# ##-- end 1st party imports
 42
 43# ##-- types
 44# isort: off
 45import abc
 46import collections.abc
 47from typing import TYPE_CHECKING, cast, assert_type, assert_never
 48from typing import Generic, NewType
 49# Protocols:
 50from typing import Protocol, runtime_checkable
 51# Typing Decorators:
 52from typing import no_type_check, final, override, overload
 53
 54if TYPE_CHECKING:
 55    from jgdv import Maybe
 56    from typing import Final
 57    from typing import ClassVar, Any, LiteralString
 58    from typing import Never, Self, Literal
 59    from typing import TypeGuard
 60    from collections.abc import Iterable, Iterator, Callable, Generator
 61    from collections.abc import Sequence, Mapping, MutableMapping, Hashable
 62
 63    type Entry = model.Entry
 64    type Field = model.Field
 65##--|
 66
 67# isort: on
 68# ##-- end types
 69
 70##-- logging
 71logging = logmod.getLogger(__name__)
 72##-- end logging
 73
[docs] 74@Proto(API.WriteTime_p) 75@Mixin(ErrorRaiser_m, FieldMatcher_m) 76class PathWriter(IdenBlockMiddleware): 77 """ 78 Relativize library paths back to strings 79 80 Can suppress errors from certain path roots on relativize, 81 using MetaBlock data: 82 MetaBlock(PathWriter.SuppressKey=[pl.Path()...]) 83 84 """ 85 86 _whitelist = ("file",) 87 SuppressKey = "PathWriter.suppress" 88 _suppress_in : list[pl.Path] 89 90 def __init__(self, *, lib_root:Maybe[pl.Path]=None, **kwargs): 91 super().__init__(**kwargs) 92 self.set_field_matchers(white=self._whitelist, black=[]) 93 self._lib_root = lib_root 94 self._suppress_in = [] 95
[docs] 96 def handle_meta_entry(self, library:Library): 97 match MetaBlock.find_in(library): 98 case None: 99 return 100 case block if PathWriter.SuppressKey not in block.data: 101 return 102 case block: 103 pass 104 105 match block.data[PathWriter.SuppressKey]: 106 case list() as xs: 107 self._suppress_in += xs 108 return 109 case x: 110 raise TypeError(f"{PathWriter.SuppressKey} is not a list, but a {type(x)}")
111
[docs] 112 def on_write(self): 113 Never()
114
[docs] 115 def transform_Entry(self, entry:Entry, library:Library): 116 match self.match_on_fields(entry, library): 117 case model.Entry() as x: 118 return [x] 119 case Exception() as err: 120 logging.warning(err) 121 return [entry] 122 case x: 123 raise TypeError(type(x), x)
124
[docs] 125 def field_h(self, field:Field, entry:Entry): 126 match field.value: 127 case str(): 128 pass 129 case pl.Path() as val if not val.exists(): 130 return ValueError(f"On Export file does not exist: {entry.key} : {val}") 131 case pl.Path() as val: 132 try: 133 as_str = val.relative_to(self._lib_root) 134 field.value = as_str 135 except ValueError: 136 if self._suppress_relative_fail(val): 137 pass 138 else: 139 field.value = str(val) 140 return ValueError(f"Failed to Relativize path {entry.key}: {val}") 141 142 return [field]
143
[docs] 144 def _suppress_relative_fail(self, val:pl.Path) -> bool: 145 for x in self._suppress_in: 146 try: 147 val.relative_to(x) 148 return True 149 except ValueError: 150 pass 151 else: 152 return False