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