Completed
Pull Request — master (#2423)
by
unknown
02:12
created

DocstyleDefinition.metadata()   A

Complexity

Conditions 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
c 1
b 0
f 0
dl 0
loc 8
rs 9.4285
1
from collections import Iterable, namedtuple
2
import os.path
3
4
from coala_utils.decorators import (
5
    enforce_signature, generate_eq, generate_repr)
6
from coala_utils.string_processing import unescape
0 ignored issues
show
Unused Code introduced by
Unused unescape imported from coala_utils.string_processing
Loading history...
7
from coalib.parsing.ConfParser import ConfParser
8
9
10
@generate_repr()
11
@generate_eq("language", "docstyle", "markers")
12
class DocstyleDefinition:
13
    """
14
    The DocstyleDefinition class holds values that identify a certain type of
15
    documentation comment (for which language, documentation style/tool used
16
    etc.).
17
    """
18
    Metadata = namedtuple("Metadata", ("param_start", "param_end",
19
                                       "return_sep"))
20
21
    @enforce_signature
22
    def __init__(self, language: str, docstyle: str, markers: (Iterable, str),
23
                 metadata: Metadata):
24
        """
25
        Instantiates a new DocstyleDefinition.
26
27
        :param language: The case insensitive programming language of the
28
                         documentation comment, e.g. ``"CPP"`` for C++ or
29
                         ``"PYTHON3"``.
30
        :param docstyle: The case insensitive documentation style/tool used
31
                         to document code, e.g. ``"default"`` or ``"doxygen"``.
32
        :param markers:  An iterable of marker/delimiter string iterables
33
                         or a single marker/delimiter string iterable that
34
                         identify a documentation comment. See ``markers``
35
                         property for more details on markers.
36
        :param metadata: A namedtuple consisting of certain attributes that
37
                         form the layout of the certain documentation comment
38
                         e.g. ``param_start`` defining the start symbol of
39
                         the parameter fields and ``param_end`` defining the
40
                         end.
41
        """
42
        self._language = language.lower()
43
        self._docstyle = docstyle.lower()
44
45
        # Check and modify tuple if only one marker_set exists.
46
        markers = tuple(markers)
47
        if len(markers) == 3 and all(isinstance(x, str) for x in markers):
48
            markers = (markers,)
49
50
        self._markers = tuple(tuple(marker_set) for marker_set in markers)
51
52
        # Check marker set dimensions.
53
        for marker_set in self._markers:
54
            length = len(marker_set)
55
            if length != 3:
56
                raise ValueError("Length of a given marker set was not 3 (was "
57
                                 "actually {}).".format(length))
58
59
        self._metadata = metadata
60
61
    @property
62
    def language(self):
63
        """
64
        The programming language.
65
66
        :return: A lower-case string defining the programming language (i.e.
67
                 "cpp" or "python").
68
        """
69
        return self._language
70
71
    @property
72
    def docstyle(self):
73
        """
74
        The documentation style/tool used to document code.
75
76
        :return: A lower-case string defining the docstyle (i.e. "default" or
77
                 "doxygen").
78
        """
79
        return self._docstyle
80
81
    @property
82
    def markers(self):
83
        """
84
        A tuple of marker sets that identify a documentation comment.
85
86
        Marker sets consist of 3 entries where the first is the start-marker,
87
        the second one the each-line marker and the last one the end-marker.
88
        For example a marker tuple with a single marker set
89
        ``(("/**", "*", "*/"),)`` would match following documentation comment:
90
91
        ::
92
93
            /**
94
             * This is documentation.
95
             */
96
97
        It's also possible to supply an empty each-line marker
98
        (``("/**", "", "*/")``):
99
100
        ::
101
102
            /**
103
             This is more documentation.
104
             */
105
106
        Markers are matched "greedy", that means it will match as many
107
        each-line markers as possible. I.e. for ``("///", "///", "///")``):
108
109
        ::
110
111
            /// Brief documentation.
112
            ///
113
            /// Detailed documentation.
114
115
        :return: A tuple of marker/delimiter string tuples that identify a
116
                 documentation comment.
117
        """
118
        return self._markers
119
120
    @property
121
    def metadata(self):
122
        """
123
        A namedtuple of certain attributes present in the documentation.
124
125
        These attributes are used to define parts of the documentation.
126
        """
127
        return self._metadata
128
129
    @classmethod
130
    @enforce_signature
131
    def load(cls, language: str, docstyle: str, coalang_dir=None):
132
        """
133
        Loads a ``DocstyleDefinition`` from the coala docstyle definition files.
134
135
        This function considers all settings inside the according coalang-files
136
        as markers.
137
138
        :param language:           The case insensitive programming language of
139
                                   the documentation comment as a string.
140
        :param docstyle:           The case insensitive documentation
141
                                   style/tool used to document code, e.g.
142
                                   ``"default"`` or ``"doxygen"``.
143
        :param coalang_dir:        Path to directory with coalang docstyle
144
                                   definition files. This replaces the default
145
                                   path if given.
146
        :raises FileNotFoundError: Raised when the given docstyle was not
147
                                   found.
148
        :raises KeyError:          Raised when the given language is not
149
                                   defined for given docstyle.
150
        :return:                   The ``DocstyleDefinition`` for given language
151
                                   and docstyle.
152
        """
153
154
        docstyle = docstyle.lower()
155
156
        language_config_parser = ConfParser(remove_empty_iter_elements=False)
157
158
        coalang_file = os.path.join(
159
            coalang_dir or os.path.dirname(__file__), docstyle + ".coalang")
160
161
        try:
162
            docstyle_settings = language_config_parser.parse(coalang_file)
163
        except FileNotFoundError:
164
            raise FileNotFoundError("Docstyle definition " + repr(docstyle) +
165
                                    " not found.")
166
167
        language = language.lower()
168
169
        try:
170
            docstyle_settings = docstyle_settings[language]
171
        except KeyError:
172
            raise KeyError("Language {!r} is not defined for docstyle {!r}."
173
                           .format(language, docstyle))
174
175
        metadata_settings = ("param_start", "param_end", "return_sep")
176
177
        metadata = cls.Metadata(*[str(docstyle_settings.get(req_setting, ""))
178
                                  for req_setting in metadata_settings])
179
180
        marker_sets = (tuple(value)
181
                       for key, value in
182
                       docstyle_settings.contents.items()
183
                       if key not in metadata_settings and
184
                       not key.startswith("comment"))
185
186
        return cls(language, docstyle, marker_sets, metadata)
187