Source code for cosapp.tools.help
"""
Tool to print the description of a CoSApp object.
"""
from typing import Union
from cosapp.patterns.visitor import Visitor
from cosapp.core.module import Module
from cosapp.ports.enum import PortType
from cosapp.ports.port import BasePort
from cosapp.tools.views.markdown import PortMarkdownFormatter
[docs]class DocVisitor(Visitor):
"""Visitor collecting and reformatting Markdown
representations of systems and ports.
"""
def __init__(self) -> None:
self.doc = []
[docs] def visit_port(self, port) -> None:
"""Formatting of port Markdown representation"""
self.add_doc(port)
if len(port) > 0:
formatter = PortMarkdownFormatter(port)
self.doc.extend(["", "### Variables", ""])
self.doc.extend(formatter.var_repr())
[docs] def visit_default(self, obj) -> None:
"""Default formatting of `obj` Markdown representation"""
self.add_doc(obj)
self.doc.append(obj._repr_markdown_())
[docs] def visit_system(self, system) -> None:
"""Formatting of system Markdown representation"""
self.visit_default(system)
[docs] def visit_driver(self, driver) -> None:
"""Formatting of driver Markdown representation"""
self.visit_default(driver)
[docs] def add_doc(self, obj) -> None:
"""Add header with `obj` class name, and docstring (if any)."""
obj_type = type(obj)
doc = self.doc
doc.extend([f"## Class: {obj_type.__name__}", ""])
indent = 0
if obj_type.__doc__:
doc.extend(["### Documentation", ""])
for line in obj_type.__doc__.split("\n"):
if indent == 0:
stripped = line.lstrip()
if (n_stripped := len(stripped)) > 0:
indent = len(line) - n_stripped
else:
stripped = line[indent:]
doc.append(stripped)
[docs]class DocDisplay:
"""Helper class to print nicely information about CoSApp classes."""
# TODO unit tests
def __init__(self, obj: Union[type, BasePort, Module], **kwargs):
"""DocDisplay constructor.
Documentation can only be built for object of type :py:class:`~cosapp.drivers.driver.Driver`,
:py:class:`~cosapp.ports.port.Port` or :py:class:`~cosapp.systems.system.System`.
Parameters
----------
- obj: `Port`, `System` or `Driver` class, or instance thereof.
Object to display.
- **kwargs:
Additional keyword arguments forwarded to class constructor,
if `obj` is a class.
"""
supported = (BasePort, Module)
if not (isinstance(obj, supported) or issubclass(obj, supported)):
raise TypeError("Only Driver, Port and System are supported for display.")
if isinstance(obj, type): # Instantiate an object
if issubclass(obj, BasePort):
obj = obj("dummy", PortType.OUT, **kwargs)
else:
obj = obj("dummy", **kwargs)
self._obj = obj
def __repr__(self) -> str:
"""Returns the documentation of the class given to this constructor
object.
Returns
-------
str
Documentation string.
"""
return self._repr_markdown_()
def _repr_markdown_(self) -> str:
"""Returns the documentation of the class given to this constructor
object.
Returns
-------
str
Documentation markdown formatted string.
"""
visitor = DocVisitor()
self._obj.accept(visitor)
return "\n".join(visitor.doc)
[docs]def display_doc(obj: Union[type, BasePort, Module], **kwargs) -> DocDisplay:
"""Display information for `Driver`, `System` or `Port` in a Jupyter notebook.
Parameters
----------
- obj: `Port`, `System` or `Driver` class, or instance thereof.
Object to display.
- **kwargs:
Additional keyword arguments forwarded to class constructor,
if `obj` is a class.
"""
return DocDisplay(obj, **kwargs)