def from_values(cls, start_line=None, start_column=None, end_line=None, end_column=None): """ Creates a new TextRange. :param start_line: The line number of the start position. The first line is 1. :param start_column: The column number of the start position. The first column is 1. :param end_line: The line number of the end position. If this parameter is ``None``, then the end position is set the same like start position and end_column gets ignored. :param end_column: The column number of the end position. :return: A TextRange. """ start = TextPosition(start_line, start_column) if end_line is None: end = None else: end = TextPosition(end_line, end_column) return cls(start, end)
def test_comparison(self): uut1 = TextPosition(None, None) uut2 = TextPosition(None, None) self.assertTrue(uut1 >= uut2) self.assertTrue(uut1 <= uut2) uut1 = TextPosition(1, 2) uut2 = TextPosition(1, 3) self.assertFalse(uut1 >= uut2) self.assertTrue(uut1 <= uut2) uut1 = TextPosition(2, None) uut2 = TextPosition(3, None) self.assertFalse(uut1 >= uut2) self.assertTrue(uut1 <= uut2) uut1 = TextPosition(None, None) uut2 = TextPosition(4, 5) self.assertTrue(uut1 >= uut2) self.assertTrue(uut1 <= uut2) uut1 = TextPosition(4, 8) uut2 = TextPosition(4, 8) self.assertTrue(uut1 >= uut2) self.assertTrue(uut2 <= uut1)
def test_extract_documentation_CPP(self): data = 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, '', 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))))
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)
def setUp(self): self.pos = [ TextPosition(1, 1), TextPosition(3, 1), TextPosition(3, 3), TextPosition(4, 3), TextPosition(5, 3) ]
def test_properties(self): uut = TextPosition(None, None) self.assertEqual(uut.line, None) self.assertEqual(uut.column, None) uut = TextPosition(7, None) self.assertEqual(uut.line, 7) self.assertEqual(uut.column, None) uut = TextPosition(8, 39) self.assertEqual(uut.line, 8) self.assertEqual(uut.column, 39)
def test_fail_instantiation(self): with self.assertRaises(ValueError): TextPosition(None, 2) with self.assertRaises(TypeError): TextPosition('hello', 3) with self.assertRaises(TypeError): TextPosition(4, 'world') with self.assertRaises(TypeError): TextPosition('double', 'string')
def test_fail_instantation(self): with self.assertRaises(ValueError): TextPosition(None, 2) with self.assertRaises(TypeError): TextPosition("hello", 3) with self.assertRaises(TypeError): TextPosition(4, "world") with self.assertRaises(TypeError): TextPosition("double", "string")
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
def __init__(self, file: str, line=None, column=None): """ Creates a new result position object that represents the position of a result in the source code. :param file: The filename. :param line: The line in file or None, the first line is 1. :param column: The column indicating the character. The first one in a line is 1. :raises TypeError: Raised when - file is not a string or None. - line or columns are no integers. """ TextPosition.__init__(self, line, column) self._file = abspath(file)
def __init__(self, file: str, line=None, column=None): """ Creates a new NlSection Position object that represents the position of a NlSection in the original source code having nested languages. :param file: The filename :param line: The line in the file or None, the first line is 1. :param column: The column indicating the character. The first one in a line is 1. :raises TypeError: Raised when - file is not a string or None - line or column are not integers """ TextPosition.__init__(self, line, column) self.file = file
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)
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)) ])
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)), ))
def test_properties(self): uut = TextRange(TextPosition(7, 2), TextPosition(7, 3)) self.assertEqual(uut.start, TextPosition(7, 2)) self.assertEqual(uut.end, TextPosition(7, 3)) uut = TextRange(TextPosition(70, 20), None) self.assertEqual(uut.start, TextPosition(70, 20)) self.assertEqual(uut.end, TextPosition(70, 20)) self.assertIs(uut.start, uut.end)
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))])
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))])
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)) ])
def test_fail_instantiation(self): with self.assertRaises(ValueError): TextRange(TextPosition(3, 4), TextPosition(2, 8)) with self.assertRaises(ValueError): TextRange(TextPosition(1, 10), TextPosition(1, 7)) with self.assertRaises(TypeError): TextRange(None, TextPosition(20, 80)) with self.assertRaises(TypeError): TextRange('string', TextPosition(200, 800)) with self.assertRaises(TypeError): TextRange(TextPosition(5, 1), 'schtring')
def test_fail_instantation(self): with self.assertRaises(ValueError): TextRange(TextPosition(3, 4), TextPosition(2, 8)) with self.assertRaises(ValueError): TextRange(TextPosition(0, 10), TextPosition(0, 7)) with self.assertRaises(TypeError): TextRange(None, TextPosition(20, 80)) with self.assertRaises(TypeError): TextRange("string", TextPosition(200, 800)) with self.assertRaises(TypeError): TextRange(TextPosition(5, 0), "schtring")
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
def test_from_values(self): # Check if invalid ranges still fail. with self.assertRaises(ValueError): TextRange.from_values(0, 10, 0, 7) uut = TextRange.from_values(1, 0, 7, 3) self.assertEqual(uut.start, TextPosition(1, 0)) self.assertEqual(uut.end, TextPosition(7, 3)) uut = TextRange.from_values(1, 0, None, 88) self.assertEqual(uut.start, TextPosition(1, 0)) self.assertEqual(uut.end, TextPosition(1, 0)) uut = TextRange.from_values(1, 0, 7, None) self.assertEqual(uut.start, TextPosition(1, 0)) self.assertEqual(uut.end, TextPosition(7, None)) # Test defaults. uut = TextRange.from_values() self.assertEqual(uut.start, TextPosition(None, None)) self.assertEqual(uut.end, TextPosition(None, None))
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)
def test_expand_full(self): empty_position = TextPosition() file = ["abc\n", "def\n", "ghi\n"] empty_range = TextRange(empty_position, empty_position) full_range = TextRange.from_values(1, 1, 3, 4) self.assertEqual(empty_range.expand(file), full_range)
def test_expand_none(self): start_position = TextPosition(2, 2) end_position = TextPosition(3, 2) file = ["abc\n", "def\n", "ghi\n"] text_range = TextRange(start_position, end_position) self.assertEqual(text_range.expand(file), text_range)