Source code for bibble.fields.field_sorter

  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
 25from jgdv import Proto, Mixin
 26import bibtexparser
 27import bibtexparser.model as model
 28from bibtexparser import middlewares as ms
 29from bibtexparser.middlewares.middleware import (BlockMiddleware,
 30                                                 LibraryMiddleware)
 31from jgdv.files.tags import SubstitutionFile
 32
 33# ##-- end 3rd party imports
 34
 35import bibble._interface as API
 36from bibble.util.middlecore import IdenBlockMiddleware
 37
 38# ##-- types
 39# isort: off
 40import abc
 41import collections.abc
 42from typing import TYPE_CHECKING, cast, assert_type, assert_never
 43from typing import Generic, NewType
 44# Protocols:
 45from typing import Protocol, runtime_checkable
 46# Typing Decorators:
 47from typing import no_type_check, final, override, overload
 48
 49if TYPE_CHECKING:
 50    from jgdv import Maybe
 51    from typing import Final
 52    from typing import ClassVar, Any, LiteralString
 53    from typing import Never, Self, Literal
 54    from typing import TypeGuard
 55    from collections.abc import Iterable, Iterator, Callable, Generator
 56    from collections.abc import Sequence, Mapping, MutableMapping, Hashable
 57
 58    type Entry = model.Entry
 59    type Field = model.Field
 60    from bibtexparser.library import Library
 61##--|
 62
 63# isort: on
 64# ##-- end types
 65
 66##-- logging
 67logging = logmod.getLogger(__name__)
 68##-- end logging
 69
[docs] 70@Proto(API.WriteTime_p) 71class FieldSorter(IdenBlockMiddleware): 72 """ Sort the entries of a field 73 firsts are exact matches that go at the front. 74 lasts are a list of patterns to match on 75 """ 76 77 _first_defaults : ClassVar[list[str]] = [] 78 _last_defaults : ClassVar[list[str]] = [] 79 80 def __init__(self, *, first:Maybe[list[str]]=None, last:Maybe[list[str]]=None, **kwargs): 81 super().__init__(**kwargs) 82 self._firsts = first or self._first_defaults 83 self._lasts = last or self._last_defaults 84 self._stem_re = re.compile("^[a-zA-Z_]+") 85
[docs] 86 def on_write(self): 87 Never()
88
[docs] 89 def field_sort_key(self, field:Field) -> str|tuple: 90 match self._stem_re.match(field.key): 91 case None: 92 key = field.key 93 case x: 94 key = x[0] 95 try: 96 return (self._lasts.index(key), field.key) 97 except ValueError: 98 return key
99
[docs] 100 def transform_Entry(self, entry:Entry, library:Library) -> list[Entry]: 101 # Get the firsts in order if they exist 102 firsts = [y for x in self._firsts if (y:=entry.get(x,None)) is not None] 103 rest, lasts = [], [] 104 for field in entry.fields: 105 match self._stem_re.match(field.key): 106 case None: 107 key = field.key 108 case x: 109 key = x[0] 110 if key in self._firsts: 111 continue 112 if key not in self._lasts: 113 rest.append(field) 114 else: 115 lasts.append(field) 116 117 # Sort the lasts 118 rest = sorted(rest, key=self.field_sort_key) 119 lasts = sorted(lasts, key=self.field_sort_key) 120 entry.fields = firsts + rest + lasts 121 return [entry]