Reports ======= .. toctree:: :hidden: api/understand.Report api/understand.ReportContext Reports are plugins that generate content for Understand to display. They support basic formatting including paragraphs, headings, trees, tables, and images. From the Understand GUI, reports can sync entities, architectures, and editor locations to other views. Discovery --------- Available reports depend on the target: a :class:`Db `, an :class:`Ent `, or an :class:`Arch `. For example, the "API Info" report is available for entities and architectures, whereas the "Batch Generate Graphs" interactive report is only available for projects. Use :meth:`Report.list ` to discover available reports. The :class:`Report ` objects returned can be used to query information about the report such as the :meth:`name ` and :meth:`description `. Reports support :class:`options `. Use :meth:`Report.options ` followed by :meth:`Options.list ` to discover available options. List catalog reports for the open project (pass a :class:`Db ` so availability matches the database):: import understand db = understand.open("/path/to/myproject.und") for r in understand.Report.list(db): print(r.name(), "-", r.description()) .. _ireport-report-generation: Generation ---------- Call :meth:`db.report() `, :meth:`ent.report() `, or :meth:`arch.report() ` to generate reports for projects, entities, and architectures respectively. Each report method has the same signature. The ``name`` of the report is required and can be either a str or an :class:`Report ` object. Report output is controlled by two parameters, the required ``filename`` parameter and the optional ``format`` parameter. Available formats are: pdf, html, txt, csv, png. The pdf format is implied by a .pdf extension on the ``filename`` argument. If a ``format`` is given, the ``filename`` parameter must be a directory. All formats other than pdf can produce multiple files. The html and txt formats produce one file per page and the csv and png formats produce one file per table/image. Multiple formats can be given, comma separated. For example, "pdf,csv" would produce the pdf report plus csv files for every table in the report. Reports can have options. See the :class:`understand.Options ` class for how to format the ``options`` argument. Some reports have multiple pages. The ``pages`` parameter controls which pages are exported. By default, all pages are exported. Common errors when generating reports include: * Failure to create. Check that the report exists and is valid for the target * Invalid or unknown option string or value. * Unrecognized output format, or the output format could not be determined from ``filename`` and ``format``. Generate the **API Info** report for an entity; a ``.pdf`` filename selects PDF output:: import understand db = understand.open("/path/to/myproject.und") fn = next(db.ents("function ~unresolved ~unknown")) fn.report("API Info", "/path/to/api_info.pdf") Pass a :class:`Report ` from :meth:`Report.list ` and a ``format`` when you want a non-PDF export; ``filename`` must then be an output **directory** (see above):: import understand db = understand.open("/path/to/myproject.und") r = understand.Report.list(db)[0] db.report(r, "/path/to/report_output", format="html") Plugin writing -------------- A report plugin must have a `name` function and a `generate` function. The `name` function identifies the report and the `generate` function creates the output. At least one `test_` function should be defined to indicate when the report is available. Use the :class:`ReportContext ` object passed to the ``init`` and ``generate`` functions to access :class:`options ` and report output methods. The generated output can link to :meth:`entities `, :meth:`locations ` and comparison database :meth:`difference views `. There are style options such as :meth:`bold `, :meth:`italic `, and :meth:`color `. The output can also be structured as a :meth:`tree ` or :meth:`table ` and include :meth:`graphs `. A sample plugin is below. :: def name(): """ Required, the name of the report. """ return "Test Report" # # The following three functions determine when the report is available. # If omitted, they're assumed false. # def test_global(db): """ Optional method, return true for project level reports """ return True def test_entity(ent): """ Optional method, return true if report is valid for the entity """ return True def test_architecture(arch): """ Optional method, return true if report is valid for the architecture """ return True # # Optional methods to support abort # def support_abort(): """ Optional method, return True if this report can be aborted. Use report.is_aborted() to check if an abort has been requested """ return False def pages(report, target): """ Optional method for multi-page reports. A report can have multiple pages which each become their own html page, or are concatenated together in a pdf export. Implement this function to return all the pageIds that belong to this report. The pageId is used to construct links, and is not shown to the user. """ return [] # Report Options def init(report, target): """ Optional method, define options that can be changed by the user """ # Define options for the user to configure like this: report.options().checkbox("test", "This is a test", True) # Report generation def generate(report, target, pageId): """ Required, generate the report The pageId parameter is optional. It will be an empty string the first time a report is generated. On subsequent generations, it can be any value returned from pages() or provided as a pageId to report.pagelink() or report.breadcrumbs() functions. """ # If the report can be valid for multiple types of objects, use # isinstance to determine the target type. if isinstance(target, understand.Arch): report.print("arch: ") if isinstance(target, understand.Ent): report.print("ent: ") if isinstance(target, understand.Db): report.print("db: ") report.bold() # This takes advantage of the fact that there is a name method # for entities, architectures, and databases. report.print(target.name()) report.nobold() report.print("\n") # retrieve options defined in init like this: option = report.options().lookup("test") report.print(f"option: {option}\n")