Source code for esmvalcore.experimental.recipe_metadata

"""API for recipe metadata."""

from typing import Optional

import pybtex
from pybtex.database.input import bibtex

from esmvalcore.config._diagnostics import DIAGNOSTICS, TAGS


[docs] class RenderError(BaseException): """Error during rendering of object."""
[docs] class Contributor: """Contains contributor (author or maintainer) information. Parameters ---------- name : str Name of the author, i.e. ``'John Doe'`` institute : str Name of the institute orcid : str, optional ORCID url """ def __init__(self, name: str, institute: str, orcid: Optional[str] = None): self.name = name self.institute = institute self.orcid = orcid def __repr__(self) -> str: """Return canonical string representation.""" return ( f"{self.__class__.__name__}({self.name!r}," f" institute={self.institute!r}, orcid={self.orcid!r})" ) def __str__(self) -> str: """Return string representation.""" string = f"{self.name} ({self.institute}" if self.orcid: string += f"; {self.orcid}" string += ")" return string def _repr_markdown_(self) -> str: """Represent using markdown renderer in a notebook environment.""" return str(self)
[docs] @classmethod def from_tag(cls, tag: str) -> "Contributor": """Return an instance of Contributor from a tag (``TAGS``). Parameters ---------- tag : str The contributor tags are defined in the authors section in ``config-references.yml``. """ mapping = TAGS.get_tag_value(section="authors", tag=tag) name = " ".join(reversed(mapping["name"].split(", "))) institute = mapping.get("institute", "No affiliation") orcid = mapping["orcid"] return cls(name=name, institute=institute, orcid=orcid)
[docs] @classmethod def from_dict(cls, attributes): """Return an instance of Contributor from a dictionary. Parameters ---------- attributes : dict Dictionary containing name / institute [/ orcid]. """ name = attributes["name"] institute = attributes["institute"] orcid = attributes.get("orcid", None) return cls(name=name, institute=institute, orcid=orcid)
[docs] class Project: """Use this class to acknowledge a project associated with the recipe. Parameters ---------- project : str The project title. """ def __init__(self, project: str): self.project = project def __repr__(self) -> str: """Return canonical string representation.""" return f"{self.__class__.__name__}({self.project!r})" def __str__(self) -> str: """Return string representation.""" string = f"{self.project}" return string
[docs] @classmethod def from_tag(cls, tag: str) -> "Project": """Return an instance of Project from a tag (``TAGS``). Parameters ---------- tag : str The project tags are defined in ``config-references.yml``. """ project = TAGS["projects"][tag] return cls(project=project)
[docs] class Reference: """Parse reference information from bibtex entries. Parameters ---------- filename : str Name of the bibtex file. Raises ------ NotImplementedError If the bibtex file contains more than 1 entry. """ def __init__(self, filename: str): parser = bibtex.Parser(strict=False) bib_data = parser.parse_file(filename) if len(bib_data.entries) > 1: raise NotImplementedError( f"{self.__class__.__name__} cannot handle bibtex files " "with more than 1 entry." ) self._bib_data = bib_data self._key, self._entry = list(bib_data.entries.items())[0] self._filename = filename
[docs] @classmethod def from_tag(cls, tag: str) -> "Reference": """Return an instance of Reference from a bibtex tag. Parameters ---------- tag : str The bibtex tags resolved as ``esmvaltool/references/{tag}.bibtex`` or the corresponding directory as defined by the diagnostics path. """ filename = DIAGNOSTICS.references / f"{tag}.bibtex" return cls(filename)
def __repr__(self) -> str: """Return canonical string representation.""" return f"{self.__class__.__name__}({self._key!r})" def __str__(self) -> str: """Return string representation.""" return self.render(renderer="plaintext") def _repr_html_(self) -> str: """Represent using markdown renderer in a notebook environment.""" return self.render(renderer="html")
[docs] def render(self, renderer: str = "html") -> str: """Render the reference. Parameters ---------- renderer : str Choose the renderer for the string representation. Must be one of: 'plaintext', 'markdown', 'html', 'latex' Returns ------- str Rendered reference """ style = "plain" # alpha, plain, unsrt, unsrtalpha backend = pybtex.plugin.find_plugin("pybtex.backends", renderer)() formatter = pybtex.plugin.find_plugin( "pybtex.style.formatting", style )() try: formatter = formatter.format_entry(self._key, self._entry) rendered = formatter.text.render(backend) except Exception as err: raise RenderError( f"Could not render {self._key!r}: {err}" ) from None return rendered