Source code for coalib.bearlib.languages.documentation.DocstyleDefinition

from collections import Iterable, namedtuple
from glob import iglob
import os.path

from coala_utils.decorators import (
    enforce_signature, generate_eq, generate_repr)
from coalib.parsing.ConfParser import ConfParser


@generate_repr()
@generate_eq('language', 'docstyle', 'markers')
[docs]class DocstyleDefinition: """ The DocstyleDefinition class holds values that identify a certain type of documentation comment (for which language, documentation style/tool used etc.). """ Metadata = namedtuple('Metadata', ('param_start', 'param_end', 'return_sep')) @enforce_signature def __init__(self, language: str, docstyle: str, markers: (Iterable, str), metadata: Metadata): """ Instantiates a new DocstyleDefinition. :param language: The case insensitive programming language of the documentation comment, e.g. ``"CPP"`` for C++ or ``"PYTHON3"``. :param docstyle: The case insensitive documentation style/tool used to document code, e.g. ``"default"`` or ``"doxygen"``. :param markers: An iterable of marker/delimiter string iterables or a single marker/delimiter string iterable that identify a documentation comment. See ``markers`` property for more details on markers. :param metadata: A namedtuple consisting of certain attributes that form the layout of the certain documentation comment e.g. ``param_start`` defining the start symbol of the parameter fields and ``param_end`` defining the end. """ self._language = language.lower() self._docstyle = docstyle.lower() # Check and modify tuple if only one marker_set exists. markers = tuple(markers) if len(markers) == 3 and all(isinstance(x, str) for x in markers): markers = (markers,) self._markers = tuple(tuple(marker_set) for marker_set in markers) # Check marker set dimensions. for marker_set in self._markers: length = len(marker_set) if length != 3: raise ValueError('Length of a given marker set was not 3 (was ' 'actually {}).'.format(length)) self._metadata = metadata @property def language(self): """ The programming language. :return: A lower-case string defining the programming language (i.e. "cpp" or "python"). """ return self._language @property def docstyle(self): """ The documentation style/tool used to document code. :return: A lower-case string defining the docstyle (i.e. "default" or "doxygen"). """ return self._docstyle @property def markers(self): """ A tuple of marker sets that identify a documentation comment. Marker sets consist of 3 entries where the first is the start-marker, the second one the each-line marker and the last one the end-marker. For example a marker tuple with a single marker set ``(("/**", "*", "*/"),)`` would match following documentation comment: :: /** * This is documentation. */ It's also possible to supply an empty each-line marker (``("/**", "", "*/")``): :: /** This is more documentation. */ Markers are matched "greedy", that means it will match as many each-line markers as possible. I.e. for ``("///", "///", "///")``): :: /// Brief documentation. /// /// Detailed documentation. :return: A tuple of marker/delimiter string tuples that identify a documentation comment. """ return self._markers @property def metadata(self): """ A namedtuple of certain attributes present in the documentation. These attributes are used to define parts of the documentation. """ return self._metadata @classmethod @enforce_signature
[docs] def load(cls, language: str, docstyle: str, coalang_dir=None): """ Loads a ``DocstyleDefinition`` from the coala docstyle definition files. This function considers all settings inside the according coalang-files as markers, except ``param_start``, ``param_end`` and ``return_sep`` which are considered as special metadata markers. .. note:: When placing new coala docstyle definition files, these must consist of only lowercase letters and end with ``.coalang``! :param language: The case insensitive programming language of the documentation comment as a string. :param docstyle: The case insensitive documentation style/tool used to document code, e.g. ``"default"`` or ``"doxygen"``. :param coalang_dir: Path to directory with coalang docstyle definition files. This replaces the default path if given. :raises FileNotFoundError: Raised when the given docstyle was not found. :raises KeyError: Raised when the given language is not defined for given docstyle. :return: The ``DocstyleDefinition`` for given language and docstyle. """ docstyle = docstyle.lower() language_config_parser = ConfParser(remove_empty_iter_elements=False) coalang_file = os.path.join( coalang_dir or os.path.dirname(__file__), docstyle + '.coalang') try: docstyle_settings = language_config_parser.parse(coalang_file) except FileNotFoundError: raise FileNotFoundError('Docstyle definition ' + repr(docstyle) + ' not found.') language = language.lower() try: docstyle_settings = docstyle_settings[language] except KeyError: raise KeyError('Language {!r} is not defined for docstyle {!r}.' .format(language, docstyle)) metadata_settings = ('param_start', 'param_end', 'return_sep') metadata = cls.Metadata(*(str(docstyle_settings.get(req_setting, '')) for req_setting in metadata_settings)) marker_sets = (tuple(value) for key, value in docstyle_settings.contents.items() if key not in metadata_settings and not key.startswith('comment')) return cls(language, docstyle, marker_sets, metadata)
@staticmethod
[docs] def get_available_definitions(): """ Returns a sequence of pairs with ``(docstyle, language)`` which are available when using ``load()``. :return: A sequence of pairs with ``(docstyle, language)``. """ language_config_parser = ConfParser(remove_empty_iter_elements=False) pattern = os.path.join(os.path.dirname(__file__), '*.coalang') for coalang_file in iglob(pattern): docstyle = os.path.splitext(os.path.basename(coalang_file))[0] # Ignore files that are not lowercase, as coalang files have to be. if docstyle.lower() == docstyle: for language in language_config_parser.parse(coalang_file): yield docstyle, language.lower()