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
26import bibtexparser
27import bibtexparser.model as model
28from bibtexparser import middlewares as ms
29from bibtexparser.middlewares.middleware import (BlockMiddleware, LibraryMiddleware)
30from jgdv import Proto, Mixin
31
32# ##-- end 3rd party imports
33
34# ##-- 1st party imports
35import bibble._interface as API
36from bibble.util.mixins import ErrorRaiser_m, FieldMatcher_m
37from bibble.util.middlecore import IdenBlockMiddleware
38
39# ##-- end 1st party imports
40
41# ##-- types
42# isort: off
43import abc
44import collections.abc
45from typing import TYPE_CHECKING, cast, assert_type, assert_never
46from typing import Generic, NewType
47# Protocols:
48from typing import Protocol, runtime_checkable
49# Typing Decorators:
50from typing import no_type_check, final, override, overload
51
52if TYPE_CHECKING:
53 from jgdv import Maybe
54 from typing import Final
55 from typing import ClassVar, Any, LiteralString
56 from typing import Never, Self, Literal
57 from typing import TypeGuard
58 from collections.abc import Iterable, Iterator, Callable, Generator
59 from collections.abc import Sequence, Mapping, MutableMapping, Hashable
60
61##--|
62
63# isort: on
64# ##-- end types
65
66##-- logging
67logging = logmod.getLogger(__name__)
68##-- end logging
69
[docs]
70@Proto(API.ReadTime_p)
71@Mixin(ErrorRaiser_m, FieldMatcher_m)
72class PathReader(IdenBlockMiddleware):
73 """
74 Convert file paths in bibliography to pl.Path's, expanding relative paths
75 according to lib_root
76 """
77
78 _whitelist = ("file",)
79
80 def __init__(self, *, lib_root:Maybe[pl.Path]=None, **kwargs):
81 super().__init__(**kwargs)
82 self._lib_root = lib_root or pl.Path.cwd()
83 self.set_field_matchers(white=kwargs.pop("whitelist", self._whitelist), black=[]) # type: ignore[attr-defined]
84
[docs]
85 def on_read(self):
86 Never()
87
[docs]
88 def transform_Entry(self, entry, library):
89 match self.match_on_fields(entry, library):
90 case model.Entry() as x:
91 return [x]
92 case Exception() as err:
93 return [self.make_error_block(entry, err)]
94 case x:
95 raise TypeError(type(x))
96
[docs]
97 def field_h(self, field, entry):
98 base = pl.Path(field.value)
99 match base.parts[0]:
100 case "/":
101 field.value = base
102 case "~":
103 field.value = base.expanduser().resolve()
104 case _:
105 field.value = self._lib_root / base
106
107 if not field.value.exists():
108 return ValueError(f"File does not exist: {field.value}")
109
110 return [field]