コード例 #1
0
    def test_DocBaseClass_extraction_CPP(self):
        data = load_testdata('data.cpp')

        # No built-in documentation for C++.
        with self.assertRaises(KeyError):
            tuple(DocBaseClass.extract(data, 'CPP', 'default'))

        docstyle_CPP_doxygen = DocstyleDefinition.load('CPP', 'doxygen')

        self.assertEqual(
            tuple(DocBaseClass.extract(data, 'CPP', 'doxygen')),
            (DocumentationComment(
                ('\n'
                 ' This is the main function.\n'
                 ' @returns Exit code.\n'
                 '          Or any other number.\n'), docstyle_CPP_doxygen, '',
                docstyle_CPP_doxygen.markers[0], TextPosition(4, 1)),
             DocumentationComment(
                 (' foobar\n'
                  ' @param xyz\n'), docstyle_CPP_doxygen, '',
                 docstyle_CPP_doxygen.markers[0], TextPosition(15, 1)),
             DocumentationComment(' Some alternate style of documentation\n',
                                  docstyle_CPP_doxygen, '',
                                  docstyle_CPP_doxygen.markers[4],
                                  TextPosition(22, 1)),
             DocumentationComment(' ends instantly', docstyle_CPP_doxygen,
                                  '\t', docstyle_CPP_doxygen.markers[0],
                                  TextPosition(26, 2)),
             DocumentationComment(
                 (' Should work\n'
                  '\n'
                  ' even without a function standing below.\n'
                  '\n'
                  ' @param foo WHAT PARAM PLEASE!?\n'), docstyle_CPP_doxygen,
                 '', docstyle_CPP_doxygen.markers[4], TextPosition(32, 1))))
コード例 #2
0
 def test_not_implemented(self):
     raw_docstyle = DocstyleDefinition('nolang', 'nostyle', ('', '', ''),
                                       self.Metadata('', '', ''))
     not_implemented = DocumentationComment(
         'some docs', raw_docstyle, None, None, None)
     with self.assertRaises(NotImplementedError):
         not_implemented.parse()
コード例 #3
0
 def test_not_implemented(self):
     raw_docstyle = DocstyleDefinition("nolang", "nostyle", ('', '', ''),
                                       self.Metadata('', '', ''))
     not_implemented = DocumentationComment(
         "some docs", raw_docstyle, None, None, None)
     with self.assertRaises(NotImplementedError):
         not_implemented.parse()
    def test_fields(self):
        c_doxygen = DocstyleDefinition.load('C', 'doxygen')
        uut = DocumentationComment('my doc', c_doxygen, ' ',
                                   ('/**', '*', '*/'), TextPosition(3, 1))

        self.assertEqual(uut.documentation, 'my doc')
        self.assertEqual(uut.language, 'c')
        self.assertEqual(uut.docstyle, 'doxygen')
        self.assertEqual(uut.indent, ' ')
        self.assertEqual(str(uut), 'my doc')
        self.assertEqual(uut.marker, ('/**', '*', '*/'))
        self.assertEqual(uut.position, TextPosition(3, 1))

        python_doxygen = DocstyleDefinition.load('python', 'doxygen')

        python_doxygen_metadata = self.Metadata('@param ', ' ', '@raises ',
                                                ' ', '@return ')

        uut = DocumentationComment('qwertzuiop', python_doxygen, '\t',
                                   ('##', '#', '#'), None)

        self.assertEqual(uut.documentation, 'qwertzuiop')
        self.assertEqual(uut.language, 'python')
        self.assertEqual(uut.docstyle, 'doxygen')
        self.assertEqual(uut.indent, '\t')
        self.assertEqual(str(uut), 'qwertzuiop')
        self.assertEqual(uut.marker, ('##', '#', '#'))
        self.assertEqual(uut.range, None)
        self.assertEqual(uut.position, None)
        self.assertEqual(uut.metadata, python_doxygen_metadata)
コード例 #5
0
    def test_extract_documentation_CPP(self):
        data = DocumentationExtractionTest.load_testdata("data.cpp")

        # No built-in documentation for C++.
        with self.assertRaises(KeyError):
            tuple(extract_documentation(data, "CPP", "default"))

        docstyle_CPP_doxygen = DocstyleDefinition.load("CPP", "doxygen")

        self.assertEqual(
            tuple(extract_documentation(data, "CPP", "doxygen")),
            (DocumentationComment(("\n"
                                   " This is the main function.\n"
                                   " @returns Exit code.\n"
                                   "          Or any other number.\n"),
                                  docstyle_CPP_doxygen.markers[0],
                                  TextRange.from_values(4, 1, 8, 4)),
             DocumentationComment(
                 (" foobar\n"
                  " @param xyz\n"), docstyle_CPP_doxygen.markers[0],
                 TextRange.from_values(15, 1, 17, 4)),
             DocumentationComment(" Some alternate style of documentation\n",
                                  docstyle_CPP_doxygen.markers[4],
                                  TextRange.from_values(22, 1, 23, 1)),
             DocumentationComment(" ends instantly",
                                  docstyle_CPP_doxygen.markers[0],
                                  TextRange.from_values(26, 5, 26, 26)),
             DocumentationComment((" Should work\n"
                                   "\n"
                                   " even without a function standing below.\n"
                                   "\n"
                                   " @param foo WHAT PARAM PLEASE!?\n"),
                                  docstyle_CPP_doxygen.markers[4],
                                  TextRange.from_values(32, 1, 37, 1))))
コード例 #6
0
 def test_not_implemented(self):
     raw_docstyle = DocstyleDefinition('nolang', 'nostyle', ('', '', ''),
                                       self.Metadata('', '', '', '', ''),
                                       self.ClassPadding('', ''),
                                       self.FunctionPadding('', ''),
                                       self.DocstringTypeRegex('', ''),
                                       '')
     not_implemented = DocumentationComment(
         'some docs', raw_docstyle, None, None, None)
     with self.assertRaises(NotImplementedError):
         not_implemented.parse()
コード例 #7
0
    def check_docstring(self, docstring, expected=[]):
        self.assertIsInstance(docstring, str,
                              "expected needs to be a string for this test.")

        self.assertIsInstance(expected, list,
                              "expected needs to be a list for this test.")

        doc_comment = DocumentationComment(docstring, "python", "default",
                                           None, None, None)
        parsed_metadata = doc_comment.parse()
        self.assertEqual(parsed_metadata, expected)
コード例 #8
0
    def check_docstring(self, docstring, expected=[]):
        self.assertIsInstance(docstring, str,
                              'expected needs to be a string for this test.')

        self.assertIsInstance(expected, list,
                              'expected needs to be a list for this test.')

        python_default = DocstyleDefinition.load('python', 'default')

        doc_comment = DocumentationComment(docstring, python_default, None,
                                           None, None)
        parsed_metadata = doc_comment.parse()
        self.assertEqual(parsed_metadata, expected)
コード例 #9
0
    def check_docstring(self, docstring, expected=[]):
        self.assertIsInstance(docstring,
                              str,
                              "expected needs to be a string for this test.")

        self.assertIsInstance(expected,
                              list,
                              "expected needs to be a list for this test.")

        doc_comment = DocumentationComment(docstring, "python", "default",
                                           None, None, None)
        parsed_metadata = doc_comment.parse()
        self.assertEqual(parsed_metadata, expected)
コード例 #10
0
    def test_fields(self):
        uut = DocumentationComment("my doc", ("/**", "*", "*/"), (25, 45))

        self.assertEqual(uut.documentation, "my doc")
        self.assertEqual(str(uut), "my doc")
        self.assertEqual(uut.marker, ("/**", "*", "*/"))
        self.assertEqual(uut.range, (25, 45))

        uut = DocumentationComment("qwertzuiop", ("##", "#", "#"), None)

        self.assertEqual(uut.documentation, "qwertzuiop")
        self.assertEqual(str(uut), "qwertzuiop")
        self.assertEqual(uut.marker, ("##", "#", "#"))
        self.assertEqual(uut.range, None)
コード例 #11
0
    def check_docstring(self, docstring, expected=[]):
        self.assertIsInstance(docstring,
                              str,
                              'expected needs to be a string for this test.')

        self.assertIsInstance(expected,
                              list,
                              'expected needs to be a list for this test.')

        python_default = DocstyleDefinition.load('python', 'default')

        doc_comment = DocumentationComment(docstring, python_default,
                                           None, None, None)
        parsed_metadata = doc_comment.parse()
        self.assertEqual(parsed_metadata, expected)
コード例 #12
0
def _extract_doc_comment_from_line(content, line, column, regex, marker_dict,
                                   docstyle_definition):
    cur_line = content[line]
    begin_match = regex.search(cur_line, column)
    if begin_match:
        indent = cur_line[:begin_match.start()]
        column = begin_match.end()
        for marker in marker_dict[begin_match.group()]:
            doc_comment = _extract_doc_comment(content, line, column, marker)
            if doc_comment is not None:
                end_line, end_column, documentation = doc_comment

                position = TextPosition(line + 1, len(indent) + 1)
                doc = DocumentationComment(documentation, docstyle_definition,
                                           indent, marker, position)

                break

        if doc_comment:
            return end_line, end_column, doc
        else:
            malformed_comment = MalformedComment(
                dedent("""\
                Please check the docstring for faulty markers. A starting
                marker has been found, but no instance of DocComment is
                returned."""), line)
            return line + 1, 0, malformed_comment

    return line + 1, 0, None
コード例 #13
0
    def test_extract_documentation_PYTHON3(self):
        data = DocumentationExtractionTest.load_testdata("data.py")

        docstyle_PYTHON3_default = DocstyleDefinition.load(
            "PYTHON3", "default")
        docstyle_PYTHON3_doxygen = DocstyleDefinition.load(
            "PYTHON3", "doxygen")

        expected = (DocumentationComment(("\n"
                                          "Module description.\n"
                                          "\n"
                                          "Some more foobar-like text.\n"),
                                         docstyle_PYTHON3_default.markers[0],
                                         TextRange.from_values(1, 1, 5, 4)),
                    DocumentationComment(
                        ("\n"
                         "A nice and neat way of documenting code.\n"
                         ":param radius: The explosion radius.\n"),
                        docstyle_PYTHON3_default.markers[0],
                        TextRange.from_values(8, 5, 11, 8)),
                    DocumentationComment(
                        ("\n"
                         "Docstring with layouted text.\n"
                         "\n"
                         "    layouts inside docs are preserved for these "
                         "documentation styles.\n"
                         "this is intended.\n"),
                        docstyle_PYTHON3_default.markers[0],
                        TextRange.from_values(14, 1, 19, 4)),
                    DocumentationComment(
                        (" Docstring directly besides triple quotes.\n"
                         "    Continues here. "),
                        docstyle_PYTHON3_default.markers[0],
                        TextRange.from_values(21, 1, 22, 24)),
                    DocumentationComment(("super\n"
                                          " nicely\n"
                                          "short"),
                                         docstyle_PYTHON3_default.markers[0],
                                         TextRange.from_values(35, 1, 37, 9)))

        self.assertEqual(
            tuple(extract_documentation(data, "PYTHON3", "default")), expected)

        # Change only the docstyle in expected results.
        expected = list(
            DocumentationComment(r.documentation, r.marker, r.range)
            for r in expected)

        expected.insert(
            4,
            DocumentationComment(
                (" Alternate documentation style in doxygen.\n"
                 "  Subtext\n"
                 " More subtext (not correctly aligned)\n"
                 "      sub-sub-text\n"
                 "\n"), docstyle_PYTHON3_doxygen.markers[1],
                TextRange.from_values(25, 1, 30, 1)))

        self.assertEqual(
            list(extract_documentation(data, "PYTHON3", "doxygen")), expected)
コード例 #14
0
    def test_extract_documentation_C(self):
        data = load_testdata("data.c")

        # No built-in documentation for C.
        with self.assertRaises(KeyError):
            tuple(extract_documentation(data, "C", "default"))

        docstyle_C_doxygen = DocstyleDefinition.load("C", "doxygen")

        expected_results = (DocumentationComment(
                                ("\n"
                                 " This is the main function.\n"
                                 "\n"
                                 " @returns Your favorite number.\n"),
                                docstyle_C_doxygen, "",
                                docstyle_C_doxygen.markers[0],
                                TextRange.from_values(3, 1, 7, 4)),
                            DocumentationComment(
                                ("\n"
                                 " Preserves alignment\n"
                                 " - Main item\n"
                                 "   - sub item\n"
                                 "     - sub sub item\n"),
                                docstyle_C_doxygen, "",
                                docstyle_C_doxygen.markers[2],
                                TextRange.from_values(15, 1, 20, 4)),
                            DocumentationComment(
                                (" ABC\n"
                                 "    Another type of comment\n"
                                 "\n"
                                 "    ..."),
                                docstyle_C_doxygen, "",
                                docstyle_C_doxygen.markers[1],
                                TextRange.from_values(23, 1, 26, 11)),
                            DocumentationComment(
                                (" foobar = barfoo.\n"
                                 " @param x whatever...\n"),
                                docstyle_C_doxygen, "",
                                docstyle_C_doxygen.markers[0],
                                TextRange.from_values(28, 1, 30, 4)))

        self.assertEqual(tuple(
            extract_documentation(data, "C", "doxygen")),
            expected_results)
コード例 #15
0
    def test_DocBaseClass_extraction_C(self):
        data = load_testdata('data.c')

        # No built-in documentation for C.
        with self.assertRaises(KeyError):
            tuple(DocBaseClass.extract(data, 'C', 'default'))

        docstyle_C_doxygen = DocstyleDefinition.load('C', 'doxygen')

        expected_results = (DocumentationComment(
                                ('\n'
                                 ' This is the main function.\n'
                                 '\n'
                                 ' @returns Your favorite number.\n'),
                                docstyle_C_doxygen, '',
                                docstyle_C_doxygen.markers[0],
                                TextPosition(3, 1)),
                            DocumentationComment(
                                ('\n'
                                 ' Preserves alignment\n'
                                 ' - Main item\n'
                                 '   - sub item\n'
                                 '     - sub sub item\n'),
                                docstyle_C_doxygen, '',
                                docstyle_C_doxygen.markers[2],
                                TextPosition(15, 1)),
                            DocumentationComment(
                                (' ABC\n'
                                 '    Another type of comment\n'
                                 '\n'
                                 '    ...'),
                                docstyle_C_doxygen, '',
                                docstyle_C_doxygen.markers[1],
                                TextPosition(23, 1)),
                            DocumentationComment(
                                (' foobar = barfoo.\n'
                                 ' @param x whatever...\n'),
                                docstyle_C_doxygen, '',
                                docstyle_C_doxygen.markers[0],
                                TextPosition(28, 1)))

        self.assertEqual(tuple(
            DocBaseClass.extract(data, 'C', 'doxygen')),
            expected_results)
コード例 #16
0
    def test_extract_documentation_CPP_2(self):
        data = DocumentationExtractionTest.load_testdata("data2.cpp")

        docstyle_CPP_doxygen = DocstyleDefinition.load("CPP", "doxygen")

        self.assertEqual(tuple(extract_documentation(
            data, "CPP", "doxygen")), (DocumentationComment(
                ("module comment\n"
                 " hello world\n"), docstyle_CPP_doxygen.markers[0],
                TextRange.from_values(1, 1, 3, 4)), ))
コード例 #17
0
    def test_extract_documentation_C_2(self):
        data = ['/** my main description\n', ' * continues here */']

        docstyle_C_doxygen = DocstyleDefinition.load('C', 'doxygen')

        self.assertEqual(list(extract_documentation(data, 'C', 'doxygen')), [
            DocumentationComment(
                ' my main description\n continues here', docstyle_C_doxygen,
                '', docstyle_C_doxygen.markers[0], TextPosition(1, 1))
        ])
コード例 #18
0
    def test_extract_documentation_C_2(self):
        data = ['/** my main description\n', ' * continues here */']

        docstyle_C_doxygen = DocstyleDefinition.load("C", "doxygen")

        self.assertEqual(list(extract_documentation(data, "C", "doxygen")), [
            DocumentationComment(" my main description\n continues here", "C",
                                 "doxygen", "", docstyle_C_doxygen.markers[0],
                                 TextRange.from_values(1, 1, 2, 21))
        ])
コード例 #19
0
    def test_extract_documentation_CPP_2(self):
        data = load_testdata('data2.cpp')

        docstyle_CPP_doxygen = DocstyleDefinition.load('CPP', 'doxygen')

        self.assertEqual(tuple(extract_documentation(
            data, 'CPP', 'doxygen')), (DocumentationComment(
                ('module comment\n'
                 ' hello world\n'), docstyle_CPP_doxygen, '',
                docstyle_CPP_doxygen.markers[0], TextPosition(1, 1)), ))
コード例 #20
0
    def test_extract_documentation_PYTHON3_2(self):
        data = ['\n', '""" documentation in single line  """\n', 'print(1)\n']

        docstyle_PYTHON3_default = DocstyleDefinition.load("PYTHON3",
                                                           "default")

        self.assertEqual(
            list(extract_documentation(data, "PYTHON3", "default")),
            [DocumentationComment(" documentation in single line  ",
                                  docstyle_PYTHON3_default.markers[0],
                                  TextRange.from_values(2, 1, 2, 38))])
コード例 #21
0
    def test_DocBaseClass_extraction_PYTHON3_2(self):
        data = ['\n', '""" documentation in single line  """\n', 'print(1)\n']

        docstyle_PYTHON3_default = DocstyleDefinition.load('PYTHON3',
                                                           'default')

        self.assertEqual(
            list(DocBaseClass.extract(data, 'PYTHON3', 'default')),
            [DocumentationComment(' documentation in single line  ',
                                  docstyle_PYTHON3_default, '',
                                  docstyle_PYTHON3_default.markers[0],
                                  TextPosition(2, 1))])
コード例 #22
0
    def test_DocBaseClass_extraction_PYTHON3_5(self):
        data = ['r"""\n', 'This is a raw docstring\n', '"""\n']

        docstyle_PYTHON3_default = DocstyleDefinition.load('PYTHON3',
                                                           'default')

        self.assertEqual(
            list(DocBaseClass.extract(data, 'PYTHON3', 'default')),
            [DocumentationComment('\nThis is a raw docstring\n',
                                  docstyle_PYTHON3_default, 'r',
                                  docstyle_PYTHON3_default.markers[0],
                                  TextPosition(1, 2))])
コード例 #23
0
    def run(self,
            filename,
            file,
            language: str,
            docstyle: str = 'default',
            allow_missing_func_desc: str = False,
            indent_size: int = 4,
            expand_one_liners: str = False):
        """
        Checks for certain in-code documentation styles.

        It currently checks for the following style: ::

            The first line needs to have no indentation.
                - Following lines can have indentation

            :param x:
                4 space indent
            :return:
                also 4 space indent
                following lines are also 4 space indented

        :param language: The programming language of the file(s).
        :param docstyle: The docstyle to use. For example ``default`` or
                         ``doxygen``. Docstyles are language dependent, meaning
                         not every language is supported by a certain docstyle.
        :param allow_missing_func_desc: When set ``True`` this will allow
                         functions with missing descriptions, allowing
                         functions to start with params.
        :param indent_size: Number of spaces per indentation level.
        :param expand_one_liners: When set ``True`` this will expand one liner
                         docstrings.
        """

        for doc_comment in self.extract(file, language, docstyle):
            parsed = doc_comment.parse()

            (new_metadata, warning_desc) = self.process_documentation(
                parsed, allow_missing_func_desc, indent_size,
                expand_one_liners)

            new_comment = DocumentationComment.from_metadata(
                new_metadata, doc_comment.docstyle_definition,
                doc_comment.marker, doc_comment.indent, doc_comment.position)

            if new_comment != doc_comment:
                # Something changed, let's apply a result.
                diff = self.generate_diff(file, doc_comment, new_comment)

                yield Result(origin=self,
                             message=warning_desc,
                             affected_code=(diff.range(filename), ),
                             diffs={filename: diff})
コード例 #24
0
    def test_extract_documentation_PYTHON3_3(self):
        data = ['## documentation in single line without return at end.']

        docstyle_PYTHON3_doxygen = DocstyleDefinition.load("PYTHON3",
                                                           "doxygen")

        self.assertEqual(
            list(extract_documentation(data, "PYTHON3", "doxygen")),
            [DocumentationComment(" documentation in single line without "
                                  "return at end.",
                                  docstyle_PYTHON3_doxygen.markers[1],
                                  TextRange.from_values(1, 1, 1, 55))])
コード例 #25
0
    def test_extract_documentation_PYTHON3_3(self):
        data = ['## documentation in single line without return at end.']

        docstyle_PYTHON3_doxygen = DocstyleDefinition.load(
            'PYTHON3', 'doxygen')

        self.assertEqual(
            list(extract_documentation(data, 'PYTHON3', 'doxygen')), [
                DocumentationComment(
                    ' documentation in single line without '
                    'return at end.', docstyle_PYTHON3_doxygen, '',
                    docstyle_PYTHON3_doxygen.markers[1], TextPosition(1, 1))
            ])
コード例 #26
0
    def test_fields(self):
        uut = DocumentationComment("my doc", "c", "default", " ",
                                   ("/**", "*", "*/"), (25, 45))

        self.assertEqual(uut.documentation, "my doc")
        self.assertEqual(uut.language, "c")
        self.assertEqual(uut.docstyle, "default")
        self.assertEqual(uut.indent, " ")
        self.assertEqual(str(uut), "my doc")
        self.assertEqual(uut.marker, ("/**", "*", "*/"))
        self.assertEqual(uut.range, (25, 45))

        uut = DocumentationComment("qwertzuiop", "python", "doxygen", "\t",
                                   ("##", "#", "#"), None)

        self.assertEqual(uut.documentation, "qwertzuiop")
        self.assertEqual(uut.language, "python")
        self.assertEqual(uut.docstyle, "doxygen")
        self.assertEqual(uut.indent, "\t")
        self.assertEqual(str(uut), "qwertzuiop")
        self.assertEqual(uut.marker, ("##", "#", "#"))
        self.assertEqual(uut.range, None)
コード例 #27
0
    def run(self, filename, file, language: str,
            docstyle: str='default', allow_missing_func_desc: str=False,
            indent_size: int=4, expand_one_liners: str=False):
        """
        Checks for certain in-code documentation styles.

        It currently checks for the following style: ::

            The first line needs to have no indentation.
                - Following lines can have indentation

            :param x:
                4 space indent
            :return:
                also 4 space indent
                following lines are also 4 space indented

        :param language: The programming language of the file(s).
        :param docstyle: The docstyle to use. For example ``default`` or
                         ``doxygen``. Docstyles are language dependent, meaning
                         not every language is supported by a certain docstyle.
        :param allow_missing_func_desc: When set ``True`` this will allow
                         functions with missing descriptions, allowing
                         functions to start with params.
        :param indent_size: Number of spaces per indentation level.
        :param expand_one_liners: When set ``True`` this will expand one liner
                         docstrings.
        """

        for doc_comment in self.extract(file, language, docstyle):
            parsed = doc_comment.parse()

            (new_metadata, warning_desc) = self.process_documentation(
                                parsed, allow_missing_func_desc, indent_size,
                                expand_one_liners)

            new_comment = DocumentationComment.from_metadata(
                new_metadata, doc_comment.docstyle_definition,
                doc_comment.marker, doc_comment.indent, doc_comment.position)

            if new_comment != doc_comment:
                # Something changed, let's apply a result.
                diff = self.generate_diff(file, doc_comment, new_comment)

                yield Result(
                    origin=self,
                    message=warning_desc,
                    affected_code=(diff.range(filename),),
                    diffs={filename: diff})
コード例 #28
0
    def test_from_metadata(self):
        data = load_testdata("default.py")

        original = list(extract_documentation(data, "python", "default"))

        parsed_docs = [(doc.parse(), doc.marker, doc.indent, doc.range)
                       for doc in original]

        docstyle_definition = DocstyleDefinition.load("python", "default")

        assembled_docs = [DocumentationComment.from_metadata(
                          doc[0], docstyle_definition, doc[1], doc[2], doc[3])
                          for doc in parsed_docs]

        self.assertEqual(assembled_docs, original)
コード例 #29
0
    def test_from_metadata(self):
        data = load_testdata('default.py')

        original = list(DocBaseClass.extract(data, 'python', 'default'))

        parsed_docs = [(doc.parse(), doc.marker, doc.indent, doc.position)
                       for doc in original]

        docstyle_definition = DocstyleDefinition.load('python', 'default')

        assembled_docs = [DocumentationComment.from_metadata(
                          doc[0], docstyle_definition, doc[1], doc[2], doc[3])
                          for doc in parsed_docs]

        self.assertEqual(assembled_docs, original)
コード例 #30
0
    def test_from_metadata(self):
        data = load_testdata('default.py')

        original = list(DocBaseClass.extract(data, 'python', 'default'))

        parsed_docs = [(doc.parse(), doc.marker, doc.indent, doc.position)
                       for doc in original]

        docstyle_definition = DocstyleDefinition.load('python', 'default')

        assembled_docs = [DocumentationComment.from_metadata(
                          doc[0], docstyle_definition, doc[1], doc[2], doc[3])
                          for doc in parsed_docs]

        self.assertEqual(assembled_docs, original)
コード例 #31
0
    def run(
            self,
            filename,
            file,
            language: str,
            docstyle: str = 'default',
            locale: str = 'en-US',
            languagetool_disable_rules: typed_list(str) = (),
    ):
        """
        Checks the main description and comments description of documentation
        with LanguageTool. LanguageTool finds many errors that a simple spell
        checker cannot detect and several grammar problems. A full list of
        rules for english language can be found here at:
        https://community.languagetool.org/rule/list?lang=en
        LanguageTool currently supports more than 25 languages. For further
        information, visit: https://www.languagetool.org/languages/

        :param language:
            The programming language of the file(s).
        :param docstyle:
            The docstyle to use. For example ``default`` or ``doxygen``.
            Docstyles are language dependent, meaning not every language is
            supported by a certain docstyle.
        :param locale:
            A locale representing the language you want to have checked.
            Default is set to 'en-US'.
        :param languagetool_disable_rules:
            List of rules to disable checks for.
        """
        for doc_comment in self.extract(file, language, docstyle):
            parsed = doc_comment.parse()

            (new_metadata, warning_desc) = self.process_documentation(
                parsed, locale, languagetool_disable_rules)

            new_comment = DocumentationComment.from_metadata(
                new_metadata, doc_comment.docstyle_definition,
                doc_comment.marker, doc_comment.indent, doc_comment.position)

            if new_comment != doc_comment:
                # Something changed, let's apply a result.
                diff = self.generate_diff(file, doc_comment, new_comment)

                yield Result(origin=self,
                             message=warning_desc,
                             affected_code=(diff.range(filename), ),
                             diffs={filename: diff})
コード例 #32
0
def _extract_doc_comment_from_line(content, line, column, regex, marker_dict):
    begin_match = regex.search(content[line], column)
    if begin_match:
        column = begin_match.end()
        for marker in marker_dict[begin_match.group()]:
            doc_comment = _extract_doc_comment(content, line, column, marker)
            if doc_comment is not None:
                end_line, end_column, documentation = doc_comment

                rng = TextRange.from_values(line + 1,
                                            begin_match.start() + 1,
                                            end_line + 1, end_column + 1)
                doc = DocumentationComment(documentation, marker, rng)

                return end_line, end_column, doc

    return line + 1, 0, None
コード例 #33
0
    def test_from_metadata(self):
        data = load_testdata("default.py")

        original = list(extract_documentation(data, "python", "default"))

        parsed_docs = [(doc.parse(), doc.marker, doc.indent, doc.range)
                       for doc in original]

        docstyle_definition = DocstyleDefinition.load("python", "default")

        assembled_docs = [
            DocumentationComment.from_metadata(doc[0], docstyle_definition,
                                               doc[1], doc[2], doc[3])
            for doc in parsed_docs
        ]

        self.assertEqual(assembled_docs, original)
コード例 #34
0
    def run(self, filename, file, language: str,
            docstyle: str = 'default',
            locale: str = 'en-US',
            languagetool_disable_rules: typed_list(str) = (),
            ):
        """
        Checks the main description and comments description of documentation
        with LanguageTool. LanguageTool finds many errors that a simple spell
        checker cannot detect and several grammar problems. A full list of
        rules for english language can be found here at:
        https://community.languagetool.org/rule/list?lang=en
        LanguageTool currently supports more than 25 languages. For further
        information, visit: https://www.languagetool.org/languages/

        :param language:
            The programming language of the file(s).
        :param docstyle:
            The docstyle to use. For example ``default`` or ``doxygen``.
            Docstyles are language dependent, meaning not every language is
            supported by a certain docstyle.
        :param locale:
            A locale representing the language you want to have checked.
            Default is set to 'en-US'.
        :param languagetool_disable_rules:
            List of rules to disable checks for.
        """
        for doc_comment in self.extract(file, language, docstyle):
            parsed = doc_comment.parse()

            (new_metadata, warning_desc) = self.process_documentation(
                parsed, locale, languagetool_disable_rules)

            new_comment = DocumentationComment.from_metadata(
                new_metadata, doc_comment.docstyle_definition,
                doc_comment.marker, doc_comment.indent, doc_comment.position)

            if new_comment != doc_comment:
                # Something changed, let's apply a result.
                diff = self.generate_diff(file, doc_comment, new_comment)

                yield Result(
                    origin=self,
                    message=warning_desc,
                    affected_code=(diff.range(filename),),
                    diffs={filename: diff})
コード例 #35
0
def _extract_doc_comment_from_line(content, line, column, regex, marker_dict,
                                   docstyle_definition):
    cur_line = content[line]
    begin_match = regex.search(cur_line, column)
    if begin_match:
        column = begin_match.end()
        indent = begin_match.group('indent')
        for marker in marker_dict[begin_match.group('marker')]:
            doc_comment = _extract_doc_comment(content, line, column, marker)
            if doc_comment is not None:
                end_line, end_column, documentation = doc_comment

                position = TextPosition(line + 1, len(indent) + 1)
                doc = DocumentationComment(documentation, docstyle_definition,
                                           indent, marker, position)

                return end_line, end_column, doc

    return line + 1, 0, None
コード例 #36
0
 def test_not_implemented(self):
     not_implemented = DocumentationComment(
         "some docs", "nolang", "doxygen", None, None, None)
     with self.assertRaises(NotImplementedError):
         not_implemented.parse()
コード例 #37
0
    def process_documentation(self,
                              doc_comment: DocumentationComment,
                              allow_missing_func_desc: str = False,
                              indent_size: int = 4,
                              expand_one_liners: str = False):
        """
        This fixes the parsed documentation comment.

        :param doc_comment:
            Contains instance of DocumentationComment.
        :param allow_missing_func_desc:
            When set ``True`` this will allow functions with missing
            descriptions, allowing functions to start with params.
        :param indent_size:
            Number of spaces per indentation level.
        :param expand_one_liners:
            When set ``True`` this will expand one liner docstrings.
        :return:
            A tuple of fixed parsed documentation comment and warning_desc.
        """
        parsed = doc_comment.parse()
        # Assuming that the first element is always the only main
        # description.
        metadata = iter(parsed)

        main_description = next(metadata)

        if main_description.desc == '\n' and not allow_missing_func_desc:
            # Triple quoted string literals doesn't look good. It breaks
            # the line of flow. Hence we use dedent.
            warning_desc = dedent("""\
            Missing function description.
            Please set allow_missing_func_desc = True to ignore this warning.
            """)
        else:
            warning_desc = 'Documentation does not have correct style.'

        # one empty line shall follow main description (except it's empty
        # or no annotations follow).
        if main_description.desc.strip() != '':
            if not expand_one_liners and len(parsed) == 1:
                main_description = main_description._replace(
                    desc=main_description.desc.strip())
            else:
                main_description = main_description._replace(
                    desc='\n' + main_description.desc.strip() + '\n' *
                    (1 if len(parsed) == 1 else 2))

        new_metadata = [main_description]
        for m in metadata:
            # Split newlines and remove leading and trailing whitespaces.
            stripped_desc = list(map(str.strip, m.desc.splitlines()))
            if len(stripped_desc) == 0:
                # Annotations should be on their own line, though no
                # further description follows.
                stripped_desc.append('')
            else:
                # Wrap parameter description onto next line if it follows
                # annotation directly.
                if stripped_desc[0] != '':
                    stripped_desc.insert(0, '')

            # Indent with 4 spaces.
            stripped_desc = ('' if line == '' else ' ' * indent_size + line
                             for line in stripped_desc)

            new_desc = '\n'.join(stripped_desc)

            # Strip away trailing whitespaces and obsolete newlines (except
            # one newline which is mandatory).
            new_desc = new_desc.rstrip() + '\n'

            new_metadata.append(m._replace(desc=new_desc.lstrip(' ')))

        new_comment = DocumentationComment.from_metadata(
            new_metadata, doc_comment.docstyle_definition, doc_comment.marker,
            doc_comment.indent, doc_comment.position)

        # Instantiate default padding.
        class_padding = doc_comment.docstyle_definition.class_padding
        function_padding = doc_comment.docstyle_definition.function_padding
        # Check if default padding exist in the coalang file.
        if (class_padding != DocstyleDefinition.ClassPadding('', '')
                and function_padding != DocstyleDefinition.FunctionPadding(
                    '', '')):
            # Check docstring_type
            if doc_comment.docstring_type == 'class':
                new_comment.top_padding = class_padding.top_padding
                new_comment.bottom_padding = class_padding.bottom_padding
            elif doc_comment.docstring_type == 'function':
                new_comment.top_padding = function_padding.top_padding
                new_comment.bottom_padding = function_padding.bottom_padding
            else:
                # Keep paddings as they are originally.
                new_comment.top_padding = doc_comment.top_padding
                new_comment.bottom_padding = doc_comment.bottom_padding
        else:
            # If there's no default paddings defined. Keep padding as
            # they are originally.
            new_comment.top_padding = doc_comment.top_padding
            new_comment.bottom_padding = doc_comment.bottom_padding

        return (new_comment, warning_desc)
コード例 #38
0
    def process_documentation(self,
                              doc_comment: DocumentationComment,
                              allow_missing_func_desc: str = False,
                              indent_size: int = 4,
                              expand_one_liners: str = False,
                              use_spaces: bool = True,
                              ):
        """
        This fixes the parsed documentation comment.

        :param doc_comment:
            Contains instance of DocumentationComment.
        :param allow_missing_func_desc:
            When set ``True`` this will allow functions with missing
            descriptions, allowing functions to start with params.
        :param indent_size:
            Number of spaces per indentation level.
        :param expand_one_liners:
            When set ``True`` this will expand one liner docstrings.
        :param use_spaces:
            Decides whether spaces are used for indentation or tabs.
        :return:
            An instance of a processed/fixed DocumentationComment.
        """
        parsed = doc_comment.parse()
        # Assuming that the first element is always the only main
        # description.
        metadata = iter(parsed)

        main_description = next(metadata)

        if main_description.desc == '\n' and not allow_missing_func_desc:
            # Triple quoted string literals doesn't look good. It breaks
            # the line of flow. Hence we use dedent.
            warning_desc = dedent("""\
            Missing function description.
            Please set allow_missing_func_desc = True to ignore this warning.
            """)
        else:
            warning_desc = 'Documentation does not have correct style.'

        # one empty line shall follow main description (except it's empty
        # or no annotations follow).
        if main_description.desc.strip() != '':
            if not expand_one_liners and len(parsed) == 1:
                main_description = main_description._replace(
                    desc=main_description.desc.strip())
            else:
                main_description = main_description._replace(
                    desc='\n' + main_description.desc.strip() + '\n' *
                         (1 if len(parsed) == 1 else 2))

        new_metadata = [main_description]
        for m in metadata:
            # Split newlines and remove leading and trailing whitespaces.
            stripped_desc = list(map(str.strip, m.desc.splitlines()))
            if len(stripped_desc) == 0:
                # Annotations should be on their own line, though no
                # further description follows.
                stripped_desc.append('')
            else:
                # Wrap parameter description onto next line if it follows
                # annotation directly.
                if stripped_desc[0] != '':
                    stripped_desc.insert(0, '')

            indent = ' ' if use_spaces else '\t'
            stripped_desc = ('' if line == '' else indent * indent_size +
                             line for line in stripped_desc)

            new_desc = '\n'.join(stripped_desc)

            # Strip away trailing whitespaces and obsolete newlines (except
            # one newline which is mandatory).
            new_desc = new_desc.rstrip() + '\n'

            new_metadata.append(m._replace(desc=new_desc.lstrip(' ')))

        new_comment = DocumentationComment.from_metadata(
            new_metadata, doc_comment.docstyle_definition,
            doc_comment.marker, doc_comment.indent, doc_comment.position)

        # Instantiate default padding.
        class_padding = doc_comment.docstyle_definition.class_padding
        function_padding = doc_comment.docstyle_definition.function_padding
        # Check if default padding exist in the coalang file.
        if (class_padding != DocstyleDefinition.ClassPadding('', '') and
                function_padding != DocstyleDefinition.FunctionPadding(
                    '', '')):
            # Check docstring_type
            if doc_comment.docstring_type == 'class':
                new_comment.top_padding = class_padding.top_padding
                new_comment.bottom_padding = class_padding.bottom_padding
            elif doc_comment.docstring_type == 'function':
                new_comment.top_padding = function_padding.top_padding
                new_comment.bottom_padding = function_padding.bottom_padding
            else:
                # Keep paddings as they are originally.
                new_comment.top_padding = doc_comment.top_padding
                new_comment.bottom_padding = doc_comment.bottom_padding
        else:
            # If there's no default paddings defined. Keep padding as
            # they are originally.
            new_comment.top_padding = doc_comment.top_padding
            new_comment.bottom_padding = doc_comment.bottom_padding

        return (new_comment, warning_desc)
コード例 #39
0
    def run(self,
            filename,
            file,
            language: str,
            docstyle: str = 'default',
            allow_missing_func_desc: str = False,
            indent_size: int = 4):
        """
        Checks for certain in-code documentation styles.

        It currently checks for the following style: ::

            The first line needs to have no indentation.
                - Following lines can have indentation

            :param x:
                4 space indent
            :return:
                also 4 space indent
                following lines are also 4 space indented

        :param language: The programming language of the file(s).
        :param docstyle: The docstyle to use. For example ``default`` or
                         ``doxygen``. Docstyles are language dependent, meaning
                         not every language is supported by a certain docstyle.
        :param allow_missing_func_desc: When set ``True`` this will allow
                         functions with missing descriptions, allowing
                         functions to start with params.
        :param indent_size: Number of spaces per indentation level.
        """
        for doc_comment in extract_documentation(file, language, docstyle):
            parsed = doc_comment.parse()
            metadata = iter(parsed)

            # Assuming that the first element is always the only main
            # description.
            main_description = next(metadata)

            if main_description.desc == '\n' and not allow_missing_func_desc:
                warning_desc = """
Missing function description.
Please set allow_missing_func_desc = True to ignore this warning.
"""
            else:
                warning_desc = 'Documentation does not have correct style.'

            # one empty line shall follow main description (except it's empty
            # or no annotations follow).
            if main_description.desc.strip() != '':
                main_description = main_description._replace(
                    desc='\n' + main_description.desc.strip() + '\n' *
                    (1 if len(parsed) == 1 else 2))

            new_metadata = [main_description]
            for m in metadata:
                # Split newlines and remove leading and trailing whitespaces.
                stripped_desc = list(map(str.strip, m.desc.splitlines()))

                if len(stripped_desc) == 0:
                    # Annotations should be on their own line, though no
                    # further description follows.
                    stripped_desc.append('')
                else:
                    # Wrap parameter description onto next line if it follows
                    # annotation directly.
                    if stripped_desc[0] != '':
                        stripped_desc.insert(0, '')

                # Indent with 4 spaces.
                stripped_desc = ('' if line == '' else ' ' * indent_size + line
                                 for line in stripped_desc)

                new_desc = '\n'.join(stripped_desc)

                # Strip away trailing whitespaces and obsolete newlines (except
                # one newline which is mandatory).
                new_desc = new_desc.rstrip() + '\n'

                new_metadata.append(m._replace(desc=new_desc.lstrip(' ')))

            new_comment = DocumentationComment.from_metadata(
                new_metadata, doc_comment.docstyle_definition,
                doc_comment.marker, doc_comment.indent, doc_comment.position)

            if new_comment != doc_comment:
                # Something changed, let's apply a result.
                diff = Diff(file)

                # We need to update old comment positions, as `assemble()`
                # prepends indentation for first line.
                old_range = TextRange.from_values(doc_comment.range.start.line,
                                                  1,
                                                  doc_comment.range.end.line,
                                                  doc_comment.range.end.column)
                diff.replace(old_range, new_comment.assemble())

                yield Result(origin=self,
                             message=warning_desc,
                             affected_code=(diff.range(filename), ),
                             diffs={filename: diff})
コード例 #40
0
    def test_extract_documentation_PYTHON3(self):
        data = load_testdata('data.py')
        docstyle_PYTHON3_default = DocstyleDefinition.load(
            'PYTHON3', 'default')
        docstyle_PYTHON3_doxygen = DocstyleDefinition.load(
            'PYTHON3', 'doxygen')

        expected = (
            DocumentationComment(('\n'
                                  'Module description.\n'
                                  '\n'
                                  'Some more foobar-like text.\n'),
                                 docstyle_PYTHON3_default, '',
                                 docstyle_PYTHON3_default.markers[0],
                                 TextPosition(1, 1)),
            DocumentationComment(('\n'
                                  'A nice and neat way of documenting code.\n'
                                  ':param radius: The explosion radius.\n'),
                                 docstyle_PYTHON3_default, ' ' * 4,
                                 docstyle_PYTHON3_default.markers[0],
                                 TextPosition(8, 5)),
            DocumentationComment('\nA function that returns 55.\n',
                                 docstyle_PYTHON3_default, ' ' * 8,
                                 docstyle_PYTHON3_default.markers[0],
                                 TextPosition(13, 9)),
            DocumentationComment(
                ('\n'
                 'Docstring with layouted text.\n'
                 '\n'
                 '    layouts inside docs are preserved for these '
                 'documentation styles.\n'
                 'this is intended.\n'), docstyle_PYTHON3_default, '',
                docstyle_PYTHON3_default.markers[0], TextPosition(19, 1)),
            DocumentationComment(
                (' Docstring directly besides triple quotes.\n'
                 '    Continues here. '), docstyle_PYTHON3_default, '',
                docstyle_PYTHON3_default.markers[0], TextPosition(26, 1)),
            DocumentationComment(('super\n'
                                  ' nicely\n'
                                  'short'), docstyle_PYTHON3_default, '',
                                 docstyle_PYTHON3_default.markers[0],
                                 TextPosition(40, 1)),
            DocumentationComment(('\n'
                                  'A bad indented docstring\n'
                                  '    Improper indentation.\n'
                                  ':param impact: The force of Impact.\n'),
                                 docstyle_PYTHON3_default, ' ' * 4,
                                 docstyle_PYTHON3_default.markers[0],
                                 TextPosition(45, 5)),
        )

        self.assertEqual(
            tuple(extract_documentation(data, 'PYTHON3', 'default')), expected)

        # Change only the docstyle in expected results.
        expected = list(
            DocumentationComment(r.documentation, docstyle_PYTHON3_doxygen,
                                 r.indent, r.marker, r.position)
            for r in expected)

        expected.insert(
            5,
            DocumentationComment(
                (' Alternate documentation style in doxygen.\n'
                 '  Subtext\n'
                 ' More subtext (not correctly aligned)\n'
                 '      sub-sub-text\n'
                 '\n'), docstyle_PYTHON3_doxygen, '',
                docstyle_PYTHON3_doxygen.markers[1], TextPosition(30, 1)))

        self.assertEqual(
            list(extract_documentation(data, 'PYTHON3', 'doxygen')), expected)