Exemplo n.º 1
0
    def get_import_string(self):
        # type: () -> ImportString
        """
        Get import string from a node.

        Returns:
            An absolute import string.
        """
        if self.source:
            return ImportString(self.source) + self.name

        return ImportString(self.name)
Exemplo n.º 2
0
    def generate_modules(self):
        # type: () -> None
        """
		Generate `<output>/README.md` file with title from `<root>/README.md` and `Modules`
		section that contains a Tree of all modules in the project.
		"""
        self._logger.debug("Generating {}".format(
            self._root_path_finder.relative(self.md_modules.path)))
        with self.md_modules as md_modules:
            if not md_modules.title:
                md_modules.title = "{} {}".format(self._project_name,
                                                  self.MODULES_TITLE)

            autogenerated_marker = "> Auto-generated documentation modules index."
            subtitle_parts = [autogenerated_marker]
            if md_modules.subtitle:
                subtitle_parts.append(md_modules.subtitle)

            subtitle_parts.append("Full list of {} project modules.".format(
                md_modules.render_md_doc_link(self.md_index,
                                              title=self._project_name)))
            md_modules.subtitle = "\n\n".join(subtitle_parts)

            modules_toc_lines = self._build_modules_toc_lines(
                import_string=ImportString(""),
                max_depth=10,
                md_document=md_modules,
                start_level=1,
            )

            md_doc_link = md_modules.render_md_doc_link(self.md_index)
            modules_toc_lines.insert(
                0, md_modules.get_toc_line(md_doc_link, level=0))

            md_modules.toc_section = "\n".join(modules_toc_lines)
Exemplo n.º 3
0
	def test_build_children(self, ModuleAnalyzerMock):
		node = MagicMock()
		node.name = "name"
		node.body = ["body"]
		node.mock_add_spec(ast.Module)
		record = ModuleRecord(node)
		record.import_string = ImportString("my_module")
		record.name = "class_node"
		class_node = MagicMock()
		class_node.name = "ClassNode"
		method_node = MagicMock()
		method_node.name = "class_method"
		method_node.body = ["class_method"]
		method_node.mock_add_spec(ast.FunctionDef)
		class_node.body = [method_node]
		class_node.decorator_list = []
		class_node.bases = []
		class_node.mock_add_spec(ast.ClassDef)
		function_node = MagicMock()
		function_node.decorator_list = []
		function_node.name = "function_node"
		function_node.body = ["function_body"]
		function_node.mock_add_spec(ast.FunctionDef)
		attribute_node = MagicMock()
		attribute_target = MagicMock()
		attribute_target.id = "attribute_target"
		attribute_target.mock_add_spec(ast.Name)
		attribute_node.targets = [attribute_target]
		attribute_node.value = "attribute_value"
		attribute_node.mock_add_spec(ast.Assign)
		import_node = MagicMock()
		import_name = MagicMock()
		import_name.name = "import_name"
		import_name_2 = MagicMock()
		import_name_2.name = "import_name_2"
		import_node.names = [import_name, import_name_2]
		import_node.mock_add_spec(ast.Import)
		ModuleAnalyzerMock().class_nodes = [class_node]
		ModuleAnalyzerMock().function_nodes = [function_node]
		ModuleAnalyzerMock().attribute_nodes = [attribute_node]
		ModuleAnalyzerMock().import_nodes = [import_node]
		self.assertIsNone(record.build_children())
		self.assertEqual(record.title, "ClassNode")
		self.assertEqual(record.class_records[0].node, class_node)
		self.assertEqual(record.function_records[0].node, function_node)
		self.assertEqual(record.attribute_records[0].node, attribute_node)
		self.assertEqual(record.import_records[0].node, import_node)
		self.assertEqual(record.import_records[0].name, "import_name")
		self.assertEqual(record.import_records[1].node, import_node)
		self.assertEqual(record.import_records[1].name, "import_name_2")
		self.assertEqual(
			record.class_records[0].import_string.value, "my_module.ClassNode"
		)
		self.assertEqual(
			record.class_records[0].method_records[0].import_string.value,
			"my_module.ClassNode.class_method",
		)
		self.assertEqual(
			record.function_records[0].import_string.value, "my_module.function_node"
		)
Exemplo n.º 4
0
    def test_generate_docs(self, PathFinderMock, MDDocumentMock,
                           ModuleRecordListMock, LoaderMock):
        source_path_mock = MagicMock()
        generator = Generator(
            project_name="test",
            input_path=Path("/input"),
            output_path=Path("/output"),
            source_paths=[source_path_mock],
        )

        MDDocumentMock().render_md_doc_link.return_value = "md_doc_link"
        MDDocumentMock().render_doc_link.return_value = "doc_link"

        module_record_mock = MagicMock()
        module_record_mock.title = "Title"
        module_record_mock.docstring = "Docstring"
        module_record_mock.import_string = ImportString("my.import.string")
        ModuleRecordListMock().__iter__ = MagicMock(
            return_value=iter([module_record_mock]))

        generator.generate_docs()

        LoaderMock.assert_called_with(output_path=Path("/output"),
                                      root_path=Path("/input"))
        PathFinderMock.assert_called_with(Path("/output"))
Exemplo n.º 5
0
    def _replace_links(self, module_record, record, md_document, docstring):
        # type: (ModuleRecord, NodeRecord, MDDocument, Text) -> Text
        parent_import_string = None
        if not record.import_string.is_top_level():
            parent_import_string = record.import_string.parent

        for match in self._short_link_re.findall(docstring):
            related_record_name = match.replace("`", "")
            related_import_string = None
            related_record = None
            target_path = md_document.path

            # find record in parent
            if parent_import_string:
                related_import_string = parent_import_string + related_record_name
                if related_import_string != record.import_string:
                    related_record = module_record.find_record(
                        related_import_string)

            # find record in module
            if not related_record:
                related_import_string = (module_record.import_string +
                                         related_record_name)
                related_record = module_record.find_record(
                    related_import_string)

            # find record globally
            if not related_record:
                related_import_string = ImportString(related_record_name)
                related_module_record = self._module_records.find_module_record(
                    related_import_string)
                if related_module_record:
                    related_record = related_module_record.find_record(
                        related_import_string)
                    target_path = self._loader.get_output_path(
                        related_module_record.source_path)

            if not related_record:
                continue

            if related_record.import_string.startswith(record.import_string):
                continue

            title = related_record.title
            anchor = md_document.get_anchor(related_record.title)
            if isinstance(related_record, AttributeRecord):
                parent_related_record = module_record.find_record(
                    related_record.import_string.parent)
                if parent_related_record:
                    anchor = md_document.get_anchor(
                        parent_related_record.title)

            link = md_document.render_doc_link(title,
                                               anchor=anchor,
                                               target_path=target_path)
            docstring = docstring.replace(match, link)
            self._logger.debug("Adding local link '{}' to '{}'".format(
                title, record.title))
        return docstring
Exemplo n.º 6
0
    def test_generate_doc(self, PathFinderMock, MDDocumentMock,
                          ModuleRecordListMock, LoaderMock):
        source_path_mock = MagicMock()
        generator = Generator(
            project_name="test",
            input_path=Path("/input"),
            output_path=Path("/output"),
            source_paths=[source_path_mock],
            raise_errors=True,
        )

        MDDocumentMock().render_md_doc_link.return_value = "md_doc_link"
        MDDocumentMock().render_doc_link.return_value = "doc_link"

        module_record_mock = MagicMock()
        module_record_mock.title = "Title"
        module_record_mock.docstring = "Docstring"
        module_record_mock.source_path = Path("/input/source.py")
        module_record_mock.import_string = ImportString("my.import.string")

        module_record_mock2 = MagicMock()
        module_record_mock2.title = "Title"
        module_record_mock2.docstring = "Docstring"
        module_record_mock2.source_path = Path("/input/source2.py")
        module_record_mock2.import_string = ImportString("my.import.string2")

        ModuleRecordListMock().__iter__ = MagicMock(
            return_value=iter([module_record_mock, module_record_mock2]))

        generator.generate_doc(Path("/input/source2.py"))

        LoaderMock.assert_called_with(output_path=Path("/output"),
                                      root_path=Path("/input"))
        PathFinderMock.assert_called_with(Path("/output"))

        ModuleRecordListMock().__iter__ = MagicMock(
            return_value=iter([module_record_mock]))
        with self.assertRaises(GeneratorError):
            generator.generate_doc(Path("/input/source2.py"))

        LoaderMock().parse_module_record.side_effect = ValueError(
            "loader_error")
        ModuleRecordListMock().__iter__ = MagicMock(
            return_value=iter([module_record_mock2]))
        with self.assertRaises(ValueError):
            generator.generate_doc(Path("/input/source2.py"))
Exemplo n.º 7
0
 def __init__(self, node):
     # type: (ast.AST) -> None
     self.docstring = ""
     self.import_string = ImportString("")
     self.node = node
     self.name = self.node.__class__.__name__
     self.title = ""
     self.is_method = False
     self.attribute_records = []  # type: List[AttributeRecord]
     self.parsed = False
     self._line_number = None  # type: Optional[int]
Exemplo n.º 8
0
 def __init__(self, node):
     # type: (ast.Module) -> None
     super(ModuleRecord, self).__init__(node)
     self.all_names = []  # type: List[Text]
     self.class_records = []  # type: List[ClassRecord]
     self.function_records = []  # type: List[FunctionRecord]
     self.import_records = []  # type: List[ImportRecord]
     self.source_path = Path("")
     self.source_lines = []  # type: List[Text]
     self.name = "module"
     self.title = ""
     self.import_string = ImportString("")
     self.import_string_map = {}  # type: Dict[ImportString, NodeRecord]
     self.docstring = self._get_docstring()
Exemplo n.º 9
0
	def test_startswith(self):
		self.assertTrue(
			ImportString("parent.parent2.value").startswith(ImportString("parent"))
		)
		self.assertTrue(
			ImportString("parent.parent2.value").startswith(
				ImportString("parent.parent2")
			)
		)
		self.assertFalse(
			ImportString("parent.parent2.value").startswith(ImportString("parent2"))
		)
		self.assertFalse(
			ImportString("parent.parent2.value").startswith(
				ImportString("parent.parent2value")
			)
		)
Exemplo n.º 10
0
    def get_module_record(self, source_path):
        # type: (Path) -> Optional[ModuleRecord]
        """
		Build `ModuleRecord` for given `source_path`.

		Arguments:
			source_path -- Absolute path to source file.

		Returns:
			A new `ModuleRecord` instance or None if there is ntohing to import.

		Raises:
			LoaderError -- If python source cannot be loaded.
		"""
        if not (source_path.parent / "__init__.py").exists():
            return None

        if source_path.name == "__init__.py" and source_path.parent == self._root_path:
            return None

        import_string = self.get_import_string(source_path)
        docstring_parts = []

        try:
            module_record = ModuleRecord.create_from_source(
                source_path, ImportString(import_string))
            module_record.build_children()
        except Exception as e:
            raise LoaderError("{} while loading {}: {}".format(
                e.__class__.__name__, source_path, e))

        if module_record.docstring:
            docstring_parts.append(module_record.docstring)

        if source_path.name == "__init__.py":
            readme_md_path = source_path.parent / "README.md"
            if readme_md_path.exists():
                docstring_parts.append(readme_md_path.read_text())

        docstring = "\n\n".join(docstring_parts)
        title, docstring = extract_md_title(docstring)
        if title:
            module_record.title = title
        module_record.docstring = docstring

        return module_record
Exemplo n.º 11
0
    def match(self, name):
        # type: (Text) -> Optional[ImportString]
        """
        Check if `name` matches or stats with a local name.

        Examples::

            import_node = ast.parse('from my_module import Name as LocalName')
            import_record = ImportRecord(import_node)

            import_record.match('LocalName')
            True

            import_record.match('LocalName.child')
            True

            import_record.match('OtherName')
            False

            import_record.match('LocalNameOther')
            False

        Returns:
            True if name is imported object itself on one of his children.
        """
        if name == self.local_name:
            return self.get_import_string()

        lookup = "{}.".format(self.local_name)
        if name.startswith(lookup):
            if self.source:
                trailing_import = name[len(lookup):]
                return ImportString("{}.{}".format(self.get_import_string(),
                                                   trailing_import))

        return None
Exemplo n.º 12
0
	def test_init(self):
		self.assertEqual(ImportString("value").value, "value")
		self.assertEqual(str(ImportString("value")), "value")
		self.assertTrue(hash(ImportString("value")))
		self.assertTrue(ImportString("value"))
		self.assertFalse(ImportString(""))
		self.assertEqual((ImportString("value") + "add").value, "value.add")
		self.assertEqual((ImportString("") + "add").value, "add")
		self.assertEqual(ImportString("value"), ImportString("value"))
		self.assertEqual(ImportString("value"), "value")
		self.assertNotEqual(ImportString("value"), ImportString("value1"))
		self.assertNotEqual(ImportString("value"), "value1")
		self.assertNotEqual(ImportString("value"), b"value")
		self.assertEqual(
			ImportString("parent.parent2.value").parent.value, "parent.parent2"
		)

		with self.assertRaises(ImportStringError):
			_ = ImportString("value").parent
Exemplo n.º 13
0
	def test_is_top_level(self):
		self.assertTrue(ImportString("value").is_top_level())
		self.assertTrue(ImportString("").is_top_level())
		self.assertFalse(ImportString("parent.value").is_top_level())