Source extensions for bibliography-io
bibliography-io can use installed CoLRev search-source packages to adapt
source-specific exports. Using bibliography-io without selecting a source does
not require CoLRev; packages are discovered only when a source is requested with
load() or loads().
Package discovery
CoLRev search-source packages register their endpoint class in the colrev
entry-point group under the search_source name. For example:
[project.entry-points.colrev]
search_source = "example_package.source:ExampleSearchSource"
The caller passes the class’s unique endpoint value as source:
records = bibliography_io.load(
"references.ris",
source="colrev.example",
source_version="2026",
)
The package class’s endpoint is used for discovery. Its CoLRev
source_identifier describes a source record’s unique-ID field and is not
used by bibliography-io to choose a package. If the requested endpoint is not
installed, OptionalBackendUnavailableError is raised. Multiple installed
classes claiming the same endpoint raise BackendExecutionError.
Loading hooks
The selected class receives format and the optional source_version on
each hook call. The format identifies the input representation, while source
version identifies provider-specific export conventions.
Text input uses preprocess() before parsing:
@classmethod
def preprocess(
cls, text: str, *, format: str, source_version: str | None
) -> str:
return text
Its default implementation returns the input text unchanged. This hook applies to text formats such as BibTeX, RIS, CSV, and NBIB.
File-based input uses preprocess_file() before parsing:
@classmethod
def preprocess_file(
cls,
path: Path,
*,
format: str,
source_version: str | None,
output_dir: Path,
) -> Path:
return path
Its default implementation returns the original path. It is currently used for
Excel formats, whose binary workbooks are parsed from a path rather than text.
If a package transforms a file, it must leave the original unchanged, write the
transformed file under output_dir, and return that file’s path. The returned
path must exist and be either the original file or inside output_dir.
Bibliography-io parses it before cleaning up the temporary directory, including
when parsing or a later hook raises an error.
Normalization and pipeline
After parsing, bibliography-io calls the selected class’s normalization hook:
@classmethod
def normalize(
cls,
records: list[dict],
*,
format: str,
source_version: str | None,
) -> dict[str, dict]:
...
The hook receives parser-level records and returns a mapping keyed by record
ID. Each key must be a non-empty string matching that record’s ID field.
The CoLRev SearchSourcePackageBaseClass default implementation assigns IDs
where needed, ensures they are unique, and indexes the records. Bibliography-io
validates the returned mapping and converts its values to the ordered list
returned by load() or loads(). Source-specific field mapping and value
transformation belong in this hook. The hook must normalize field names; before
return, bibliography-io converts every non-string field value to a string, so
callers can rely on normalized string-valued fields from load() and
loads() regardless of the hook’s intermediate value types.
In brief, the pipeline is:
Resolve the format and discover the requested endpoint.
Apply
preprocess()to text input orpreprocess_file()to file-based input.Parse raw records using the format parser.
Apply source normalization and return the records as a list.
Without source, load() skips source hooks and applies generic
normalization. The raw load_raw() and loads_raw() APIs bypass source
hooks and return parser-level records. loads() supports source hooks for
text input; Excel requires a file path and is not supported by loads().
For the public function signatures and return types, see API reference. For user-facing loading examples, see Usage.