Source code for bibble.latex._util

  1#!/usr/bin/env python3
  2"""
  3
  4"""
  5# Imports:
  6from __future__ import annotations
  7
  8# ##-- stdlib imports
  9import datetime
 10import enum
 11import functools as ftz
 12import itertools as itz
 13import logging as logmod
 14import pathlib as pl
 15import re
 16import time
 17import types
 18import collections
 19import contextlib
 20import hashlib
 21from copy import deepcopy
 22from uuid import UUID, uuid1
 23from weakref import ref
 24import atexit # for @atexit.register
 25import faulthandler
 26# ##-- end stdlib imports
 27
 28from pylatexenc.latexencode import (RULE_REGEX, UnicodeToLatexConversionRule,
 29                                    UnicodeToLatexEncoder)
 30from pylatexenc.latex2text import (LatexNodes2Text, MacroTextSpec,
 31                                   get_default_latex_context_db)
 32from pylatexenc.macrospec import LatexContextDb
 33
 34from bibtexparser import model
 35
 36from . import _interface as LAPI
 37from jgdv import Mixin
 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# from dataclasses import InitVar, dataclass, field
 49# from pydantic import BaseModel, Field, model_validator, field_validator, ValidationError
 50
 51if TYPE_CHECKING:
 52    from jgdv import Maybe, VList
 53    from typing import Final
 54    from typing import ClassVar, Any, LiteralString
 55    from typing import Never, Self, Literal
 56    from typing import TypeGuard
 57    from collections.abc import Iterable, Iterator, Callable, Generator
 58    from collections.abc import Sequence, Mapping, MutableMapping, Hashable
 59
 60    type U2LRule = UnicodeToLatexConversionRule
 61    type Entry = model.Field
 62    type Block = model.Block
 63    from bibtexparser.library import Library
 64##--|
 65
 66# isort: on
 67# ##-- end types
 68
 69##-- logging
 70logging = logmod.getLogger(__name__)
 71##-- end logging
 72
 73# Vars:
 74
 75# Body:
 76
[docs] 77class UnicodeHelper_m: 78 """ 79 A Helper for using pylatexenc 80 81 Builds Encoders using lists of str pairs 82 and Decoders using dicts 83 """ 84
[docs] 85 @staticmethod 86 def prep_encode_tuples(tuples:list) -> list: 87 """ prep tuples of str,str for conversion rules, 88 as re.Pattern,str 89 """ 90 result = [] 91 for x,y in tuples: 92 assert(isinstance(y, str)) 93 match x: 94 case str(): 95 result.append((re.compile(x), y)) 96 case re.Pattern(): 97 result.append((x, y)) 98 case x: 99 raise TypeError(type(x)) 100 else: 101 return result
102
[docs] 103 @staticmethod 104 def build_encode_rule(tuples:list) -> U2LRule: 105 compiled = UnicodeHelper_m.prep_encode_tuples(tuples) 106 return UnicodeToLatexConversionRule(rule_type=RULE_REGEX, rule=compiled)
107
[docs] 108 @staticmethod 109 def build_decode_rule(pair:tuple) -> MacroTextSpec: 110 name, replacement = pair 111 return MacroTextSpec(name, simplify_repl=replacement)
112
[docs] 113 @staticmethod 114 def build_encoder(*, rules:list[str|U2LRule], kwargs:dict) -> UnicodeToLatexEncoder: 115 if any(not isinstance(x, str|UnicodeToLatexConversionRule) for x in rules): 116 raise TypeError("Encoding Rules need to be UniicodeToLatexConversionRules, use LatexWriter.build_encode_rule") 117 118 rules.append(LAPI.DEFAULT_RULES_K) 119 logging.debug("Building Latex Encoder: %s", rules) 120 return UnicodeToLatexEncoder(conversion_rules=rules, **kwargs)
121
[docs] 122 @staticmethod 123 def build_decoder(*, rules:dict[str,VList[MacroTextSpec]], kwargs:dict) -> LatexNodes2Text: 124 context_db : LatexContextDb = get_default_latex_context_db() 125 logging.debug("Building Latex Decoder: %s", rules) 126 for cat, y in rules.items(): 127 match y: 128 case list() if all(isinstance(y2, MacroTextSpec) for y2 in y): 129 context_db.add_context_category(cat, prepend=True, macros=y) 130 case MacroTextSpec(): 131 context_db.add_context_category(cat, prepend=True, macros=[y]) 132 case _: 133 raise TypeError("Bad Decode Rules Specified", cat, y) 134 135 return LatexNodes2Text(latex_context=context_db, **kwargs)
136
[docs] 137 def rebuild_encoder(self, *, rules:Maybe[list[U2LRule]]=None, **kwargs) -> None: 138 """ Accumulates rules and rebuilds the encoder """ 139 self._total_rules += [x for x in (rules or []) if x not in self._total_rules] 140 self._total_options.update(kwargs) 141 self._encoder = self.build_encoder(rules=self._total_rules[:], kwargs=self._total_options)
142
[docs] 143 def rebuild_decoder(self, *, rules:dict=None, **kwargs) -> None: 144 self._total_rules.update(rules or {}) 145 self._total_options.update(kwargs) 146 self._decoder = self.build_decoder(rules=self._total_rules, kwargs=self._total_options)
147
[docs] 148 def _test_encode(self, text) -> str: 149 """ utility to test latex encoding """ 150 return self._encoder.unicode_to_latex(text)
151
[docs] 152 def _test_decode(self, text:str) -> str: 153 """ utility to test decoding """ 154 return self._decoder.latex_to_text(text)