Source code for bibble.util.name_parts

  1#!/usr/bin/env python3
  2"""
  3Refactored from bibtexparser.middlewares.names
  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 collections
 20import contextlib
 21import hashlib
 22from copy import deepcopy
 23from uuid import UUID, uuid1
 24from weakref import ref
 25import atexit # for @atexit.register
 26import faulthandler
 27# ##-- end stdlib imports
 28
 29# ##-- types
 30# isort: off
 31import abc
 32import collections.abc
 33from typing import TYPE_CHECKING, cast, assert_type, assert_never
 34from typing import Generic, NewType
 35# Protocols:
 36from typing import Protocol, runtime_checkable
 37# Typing Decorators:
 38from typing import no_type_check, final, override, overload
 39# from dataclasses import InitVar, dataclass, field
 40# from pydantic import BaseModel, Field, model_validator, field_validator, ValidationError
 41
 42if TYPE_CHECKING:
 43    from jgdv import Maybe, M_
 44    from typing import Final
 45    from typing import ClassVar, Any, LiteralString
 46    from typing import Never, Self, Literal
 47    from typing import TypeGuard
 48    from collections.abc import Iterable, Iterator, Callable, Generator
 49    from collections.abc import Sequence, Mapping, MutableMapping, Hashable
 50
 51    type MbList = Maybe[list[str]]
 52##--|
 53
 54# isort: on
 55# ##-- end types
 56
 57##-- logging
 58logging = logmod.getLogger(__name__)
 59##-- end logging
 60
 61# Vars:
 62JOIN_STR : Final[str] = ", "
 63# Body:
 64
[docs] 65def escape_last_slash(string: str) -> str: 66 """Escape the last slash in a string if it is not escaped.""" 67 # Find the number of trailing slashes 68 stripped = string.rstrip("\\") 69 num_slashes = len(string) - len(stripped) 70 if num_slashes % 2 == 0: 71 # Even number: everything is escaped 72 return string 73 else: 74 # Odd number: need to escape one. 75 return string + "\\"
76 77##--| 78
[docs] 79class NameParts_d: 80 """A dataclass representing the parts of a person name. 81 82 The different parts are defined according to BibTex's implementation 83 of name parts (first, von, last, jr). 84 """ 85 __slots__ = ("first", "von", "last", "jr") 86 87 first : list[str] 88 von : list[str] 89 last : list[str] 90 jr : list[str] 91 92 def __init__(self, *, first:MbList=None, von:MbList=None, last:MbList=None, jr:MbList=None): 93 self.first = first or [] 94 self.von = von or [] 95 self.last = last or [] 96 self.jr = jr or [] 97
[docs] 98 def merge(self, *, format:Maybe[list[str]]=None) -> str: 99 match format: 100 case None: 101 format = ["von_last", "jr", "first"] 102 case str(): 103 pass 104 case x: 105 raise TypeError(type(x)) 106 107 parts = { 108 "first" : " ".join(self.first) if self.first else None, 109 "von" : " ".join(self.von) if self.von else None, 110 "last" : " ".join(self.last) if self.last else None, 111 "jr" : " ".join(self.jr) if self.jr else None, 112 } 113 parts['von_last'] = " ".join(name for name in [parts['von'], parts['last']] if name) 114 ordered = [parts[x] for x in format] 115 return JOIN_STR.join(escape_last_slash(name) for name in ordered if name)
116 117 def __repr__(self) -> str: 118 return f"<{self.__class__.__name__} : {self.merge()}>"