citeformer.render.formatters._base

CitationFormatter ABC + shared CSL-JSON helpers.

Each concrete formatter (APA, MLA, Chicago, IEEE, Nature, Vancouver) subclasses CitationFormatter and implements inline() + bibliography(). Shared plumbing — author parsing, year extraction, page-range dashes, DOI/URL rendering — lives here so styles stay focused on their specific formatting quirks.

Module Contents

Classes

Author

Normalized CSL-JSON author record.

CitationFormatter

Abstract base class for home-grown CSL style formatters.

Functions

parse_authors

Convert CSL-JSON author dicts to Author records.

parse_year

Extract a 4-digit year from a CSL issued field.

get_str

Return a stripped non-empty string value for key, or None.

get_title

Return the item’s title, falling back to an empty string.

format_page_range

Normalise a CSL page value, using the requested dash for ranges.

ensure_period

Return text guaranteed to end in a period (no double-period).

collapse_periods

Collapse runs of .. / ... / etc. into a single period.

format_doi

Render a DOI as a full https://doi.org/… URL.

Data

API

citeformer.render.formatters._base.CSLItem

None

citeformer.render.formatters._base.CitationFormatKind

None

class citeformer.render.formatters._base.Author

Normalized CSL-JSON author record.

A CSL author is one of:

  • {"family": "...", "given": "..."} — personal name with family+given parts.

  • {"literal": "..."} — institutional / single-token / non-decomposable.

We keep both forms in one dataclass so downstream formatters can pick the field they need without branching on dict keys.

Attributes: family: Family / last name (empty for literal-only authors). given: Given / first name(s) (may be empty). literal: Non-decomposable name form (empty for personal names).

family: str = <Multiline-String>
given: str = <Multiline-String>
literal: str = <Multiline-String>
property is_literal: bool
property given_initials: str

Return the given name(s) as initials: "Edgar Allan""E. A.".

Handles hyphenated names ("Jean-Paul""J.-P.") and existing dotted initials ("E. A.""E. A.").

citeformer.render.formatters._base.parse_authors(raw: list[dict[str, Any]] | None) list[citeformer.render.formatters._base.Author]

Convert CSL-JSON author dicts to Author records.

Defensive: entries missing both family and literal are skipped. given alone (no family) is promoted to literal.

citeformer.render.formatters._base.parse_year(issued: dict[str, Any] | None) int | None

Extract a 4-digit year from a CSL issued field.

Accepts {"date-parts": [[year, ...]]} (the canonical CSL form).

citeformer.render.formatters._base.get_str(item: citeformer.render.formatters._base.CSLItem, key: str) str | None

Return a stripped non-empty string value for key, or None.

citeformer.render.formatters._base.get_title(item: citeformer.render.formatters._base.CSLItem) str

Return the item’s title, falling back to an empty string.

CSL title can be either a string or (rarely) a list; we coerce.

citeformer.render.formatters._base.format_page_range(pages: str | None, *, dash: str = '–') str | None

Normalise a CSL page value, using the requested dash for ranges.

"45-67""45–67" (en-dash by default; some styles want en-dash, some hyphen, some a special range indicator).

citeformer.render.formatters._base.ensure_period(text: str) str

Return text guaranteed to end in a period (no double-period).

Used to terminate author-list chunks where a trailing initial may already end in .. "Smith, E. A." stays as-is; "Smith""Smith.".

citeformer.render.formatters._base.collapse_periods(text: str) str

Collapse runs of .. / ... / etc. into a single period.

Used as a final post-processing step in the render layer — the per-style formatters have many sites that stack . on top of user-supplied CSL-JSON values that themselves end in . (journal names, publishers, URLs, titles). Rather than audit every emission site, we collapse pathological sequences at the end.

Bibliographic prose almost never contains legitimate ellipses, so the simple “2+ dots → 1 dot” collapse is safe in practice. If a future style needs to preserve ... in quoted titles, swap this for a smarter collapse.

citeformer.render.formatters._base.format_doi(doi: str | None) str | None

Render a DOI as a full https://doi.org/… URL.

class citeformer.render.formatters._base.CitationFormatter

Bases: abc.ABC

Abstract base class for home-grown CSL style formatters.

Subclasses must declare name + citation_format class variables and implement inline() + bibliography(). Formatters are stateless by contract; one instance can render many items concurrently (though we typically instantiate per Citeformer call for clarity).

Attributes: name: Canonical style identifier (e.g. "apa-7"). citation_format: CSL citation-format classification. Drives the Reference.inline_marker user sees and informs downstream tooling about what kind of marker to expect.

name: str

None

citation_format: citeformer.render.formatters._base.CitationFormatKind

None

abstractmethod inline(item: citeformer.render.formatters._base.CSLItem, number: int) str

Render the inline citation marker for a cited item.

Args: item: The CSL-JSON item being cited. number: 1-indexed position in the bibliography.

Returns: The style’s native inline form — e.g. "(Smith, 2023)" for author-date styles, "[1]" for numeric styles.

abstractmethod bibliography(item: citeformer.render.formatters._base.CSLItem, number: int) str

Render the full bibliography entry for an item.

Args: item: The CSL-JSON item being cited. number: 1-indexed position in the bibliography (used by numeric styles to render the leading "[1]" / "1.").

Returns: The full bibliography entry as a single plain-text string.