Primary Class ExhaleRoot Reference

class exhale.ExhaleRoot(breatheRoot, rootDirectory, rootFileName, rootFileTitle, rootFileDescription, rootFileSummary, createTreeView)

The full representation of the hierarchy graphs. In addition to containing specific lists of ExhaleNodes of interest, the ExhaleRoot class is responsible for comparing the parsed breathe hierarchy and rebuilding lost relationships using the Doxygen xml files. Once the graph parsing has finished, the ExhaleRoot generates all of the relevant reStructuredText documents and links them together.

The ExhaleRoot class is not designed for reuse at this time. If you want to generate a new hierarchy with a different directory or something, changing all of the right fields may be difficult and / or unsuccessful. Refer to the bottom of the source code for exhale.generate() for safe usage (just exception handling), but the design of this class is to be used as follows:

textRoot = ExhaleRoot(... args ...)
textRoot.parse()
textRoot.generateFullAPI()

Zero checks are in place to enforce this usage, and if you are modifying the execution of this class and things are not working make sure you follow the ordering of those methods.

Parameters:
breatheRoot (instance)

Type unknown, this is the return value of breathe.breathe_parse.

rootDirectory (str)

The name of the root directory to put everything in. This should be the value of the key containmentFolder in the dictionary passed to exhale.generate().

rootFileName (str)

The name of the file the root library api will be put into. This should not contain the rootDirectory path. This should be the value of the key rootFileName in the dictionary passed to exhale.generate().

rootFileTitle (str)

The title to be written to the top of rootFileName. This should be the value of the key rootFileTitle in the dictionary passed to exhale.generate().

rootFileDescription (str)

The description of the library api file placed after rootFileTitle. This should be the value of the key afterTitleDescription in the dictionary passed to exhale.generate().

rootFileSummary (str)

The summary of the library api placed after the generated hierarchy views. This should be the value of the key afterBodySummary in the dictionary passed to exhale.generate().

createTreeView (bool)

Creates the raw html unordered lists for use with collapsibleList if True. Otherwise, creates standard reStructuredText bulleted lists. Should be the value of the key createTreeView in the dictionary passed to exhale.generate().

Attributes:
breathe_root (instance)

The value of the parameter breatheRoot.

root_directory (str)

The value of the parameter rootDirectory.

root_file_name (str)

The value of the parameter rootFileName.

full_root_file_path (str)

The full file path of the root file ("root_directory/root_file_name").

root_file_title (str)

The value of the parameter rootFileTitle.

root_file_description (str)

The value of the parameter rootFileDescription.

root_file_summary (str)

The value of the parameter rootFileSummary.

class_view_file (str)

The full file path the class view hierarchy will be written to. This is incorporated into root_file_name using an .. include: directive.

directory_view_file (str)

The full file path the file view hierarchy will be written to. This is incorporated into root_file_name using an .. include: directive.

unabridged_api_file (str)

The full file path the full API will be written to. This is incorporated into root_file_name using a .. toctree: directive with a :maxdepth: according to the value of the key fullToctreeMaxDepth in the dictionary passed into exhale.generate().

use_tree_view (bool)

The value of the parameter createTreeView.

all_compounds (list)

A list of all the Breathe compound objects discovered along the way. Populated during exhale.ExhaleRoot.discoverAllNodes().

all_nodes (list)

A list of all of the ExhaleNode objects created. Populated during exhale.ExhaleRoot.discoverAllNodes().

node_by_refid (dict)

A dictionary with string ExhaleNode refid values, and values that are the ExhaleNode it came from. Storing it this way is convenient for when the Doxygen xml file is being parsed.

class_like (list)

The full list of ExhaleNodes of kind struct or class

defines (list)

The full list of ExhaleNodes of kind define.

enums (list)

The full list of ExhaleNodes of kind enum.

enum_values (list)

The full list of ExhaleNodes of kind enumvalue. Populated, not used.

functions (list)

The full list of ExhaleNodes of kind function.

dirs (list)

The full list of ExhaleNodes of kind dir.

files (list)

The full list of ExhaleNodes of kind file.

groups (list)

The full list of ExhaleNodes of kind group. Pupulated, not used.

namespaces (list)

The full list of ExhaleNodes of kind namespace.

typedefs (list)

The full list of ExhaleNodes of kind typedef.

unions (list)

The full list of ExhaleNodes of kind union.

variables (list)

The full list of ExhaleNodes of kind variable.

parse()

The first method that should be called after creating an ExhaleRoot object. The Breathe graph is parsed first, followed by the Doxygen xml documents. By the end of this method, all of the self.<breathe_kind>, self.all_compounds, and self.all_nodes lists as well as the self.node_by_refid dictionary will be populated. Lastly, this method sorts all of the internal lists. The order of execution is exactly

  1. exhale.ExhaleRoot.discoverAllNodes()
  2. exhale.ExhaleRoot.reparentAll()
  3. Populate self.node_by_refid using self.all_nodes.
  4. exhale.ExhaleRoot.fileRefDiscovery()
  5. exhale.ExhaleRoot.filePostProcess()
  6. exhale.ExhaleRoot.sortInternals()
discoverAllNodes()

Stack based traversal of breathe graph, creates some parental relationships between different ExhaleNode objects. Upon termination, this method will have populated the lists self.all_compounds, self.all_nodes, and the self.<breathe_kind> lists for different types of objects.

trackNodeIfUnseen(node)

Helper method for exhale.ExhaleRoot.discoverAllNodes(). If the node is not in self.all_nodes yet, add it to both self.all_nodes as well as the corresponding self.<breathe_kind> list.

Parameters:
node (ExhaleNode)

The node to begin tracking if not already present.

discoverNeigbors(nodesRemaining, node)

Helper method for exhale.ExhaleRoot.discoverAllNodes(). Some of the compound objects received from Breathe have a member function get_member() that returns all of the children. Some do not. This method checks to see if the method is present first, and if so performs the following:

For every compound in node.compound.get_member():
    If compound not present in self.all_compounds:
        - Add compound to self.all_compounds
        - Create a child ExhaleNode
        - If it is not a class, struct, or union, add to nodesRemaining
        - If it is not an enumvalue, make it a child of node parameter
Parameters:
nodesRemaining (list)

The list of nodes representing the stack traversal being done by exhale.ExhaleRoot.discoverAllNodes(). New neighbors found will be appended to this list.

node (ExhaleNode)

The node we are trying to discover potential new neighbors from.

reparentAll()

Fixes some of the parental relationships lost in parsing the Breathe graph. File relationships are recovered in exhale.ExhaleRoot.fileRefDiscovery(). This method simply calls in this order:

  1. exhale.ExhaleRoot.reparentUnions()
  2. exhale.ExhaleRoot.reparentClassLike()
  3. exhale.ExhaleRoot.reparentDirectories()
  4. exhale.ExhaleRoot.renameToNamespaceScopes()
  5. exhale.ExhaleRoot.reparentNamespaces()
reparentUnions()

Helper method for exhale.ExhaleRoot.reparentAll(). Namespaces and classes should have the unions defined in them to be in the child list of itself rather than floating around. Union nodes that are reparented (e.g. a union defined in a class) will be removed from the list self.unions since the Breathe directive for its parent (e.g. the class) will include the documentation for the union. The consequence of this is that a union defined in a class will not appear in the full api listing of Unions.

reparentClassLike()

Helper method for exhale.ExhaleRoot.reparentAll(). Iterates over the self.class_like list and adds each object as a child to a namespace if the class, or struct is a member of that namespace. Many classes / structs will be reparented to a namespace node, these will remain in self.class_like. However, if a class or struct is reparented to a different class or struct (it is a nested class / struct), it will be removed from so that the class view hierarchy is generated correctly.

reparentDirectories()

Helper method for exhale.ExhaleRoot.reparentAll(). Adds subdirectories as children to the relevant directory ExhaleNode. If a node in self.dirs is added as a child to a different directory node, it is removed from the self.dirs list.

renameToNamespaceScopes()

Helper method for exhale.ExhaleRoot.reparentAll(). Some compounds in Breathe such as functions and variables do not have the namespace name they are declared in before the name of the actual compound. This method prepends the appropriate (nested) namespace name before the name of any child that does not already have it.

For example, the variable MAX_DEPTH declared in namespace external would have its ExhaleNode’s name attribute changed from MAX_DEPTH to external::MAX_DEPTH.

reparentNamespaces()

Helper method for exhale.ExhaleRoot.reparentAll(). Adds nested namespaces as children to the relevant namespace ExhaleNode. If a node in self.namespaces is added as a child to a different namespace node, it is removed from the self.namespaces list. Because these are removed from self.namespaces, it is important that exhale.ExhaleRoot.renameToNamespaceScopes() is called before this method.

fileRefDiscovery()

Finds the missing components for file nodes by parsing the Doxygen xml (which is just the doxygen_output_dir/node.refid). Additional items parsed include adding items whose refid tag are used in this file, the <programlisting> for the file, what it includes and what includes it, as well as the location of the file (with respsect to the Doxygen root).

Care must be taken to only include a refid found with specific tags. The parsing of the xml file was done by just looking at some example outputs. It seems to be working correctly, but there may be some subtle use cases that break it.

Warning

Some enums, classes, variables, etc declared in the file will not have their associated refid in the declaration of the file, but will be present in the <programlisting>. These are added to the files’ list of children when they are found, but this parental relationship cannot be formed if you set XML_PROGRAMLISTING = NO with Doxygen. An example of such an enum would be an enum declared inside of a namespace within this file.

filePostProcess()

The real name of this method should be reparentFiles, but to avoid confusion with what stage this must happen at it is called this instead. After the exhale.ExhaleRoot.fileRefDiscovery() method has been called, each file will have its location parsed. This method reparents files to directories accordingly, so the file view hierarchy can be complete.

sortInternals()

Sort all internal lists (class_like, namespaces, variables, etc) mostly how doxygen would, alphabetical but also hierarchical (e.g. structs appear before classes in listings). Some internal lists are just sorted, and some are deep sorted (exhale.ExhaleRoot.deepSortList()).

deepSortList(lst)

For hierarchical internal lists such as namespaces, we want to sort both the list as well as have each child sort its children by calling exhale.ExhaleNode.typeSort().

Parameters:
lst (list)

The list of ExhaleNode objects to be deep sorted.

generateFullAPI()

Since we are not going to use some of the breathe directives (e.g. namespace or file), when representing the different views of the generated API we will need:

  1. Generate a single file restructured text document for all of the nodes that have either no children, or children that are leaf nodes.
  2. When building the view hierarchies (class view and file view), provide a link to the appropriate files generated previously.

If adding onto the framework to say add another view (from future import groups) you would link from a restructured text document to one of the individually generated files using the value of link_name for a given ExhaleNode object.

This method calls in this order:

  1. exhale.ExhaleRoot.generateAPIRootHeader()
  2. exhale.ExhaleRoot.generateNodeDocuments()
  3. exhale.ExhaleRoot.generateAPIRootBody()
  4. exhale.ExhaleRoot.generateAPIRootSummary()
generateAPIRootHeader()

This method creates the root library api file that will include all of the different hierarchy views and full api listing. If self.root_directory is not a current directory, it is created first. Afterward, the root API file is created and its title is written, as well as the value of self.root_file_description.

generateNodeDocuments()

Creates all of the reStructuredText documents related to types parsed by Doxygen. This includes all leaf-like documents (class, struct, enum, typedef, union, variable, and define), as well as namespace, file, and directory pages.

During the reparenting phase of the parsing process, nested items were added as a child to their actual parent. For classes, structs, enums, and unions, if it was reparented to a namespace it will remain in its respective self.<breathe_kind> list. However, if it was an internally declared child of a class or struct (nested classes, structs, enums, and unions), this node will be removed from its self.<breathe_kind> list to avoid duplication in the class hierarchy generation.

When generating the full API, though, we will want to include all of these and therefore must call exhale.ExhaleRoot.generateSingleNodeRST() with all of the nested items. For nested classes and structs, this is done by just calling node.findNestedClassLike for every node in self.class_like. The resulting list then has all of self.class_like, as well as any nested classes and structs found. With enum and union, these would have been reparented to a class or struct if it was removed from the relevant self.<breathe_kind> list. Meaning we must make sure that we genererate the single node RST documents for everything by finding the nested enums and unions from self.class_like, as well as everything in self.enums and self.unions.

Sets the file_name and link_name for the specified node. If the kind of this node is “file”, then this method will also set the program_file as well as the program_link_name fields.

Since we are operating inside of a containmentFolder, this method will include self.root_directory in this path so that you can just use:

with open(node.file_name, "w") as gen_file:
    ... write the file ...

Having the containmentFolder is important for when we want to generate the file, but when we want to use it with include or toctree this will need to change. Refer to exhale.ExhaleRoot.gerrymanderNodeFilenames().

This method also sets the value of node.title, which will be used in both the reStructuredText document of the node as well as the links generated in the class view hierarchy (<a href=”...”> for the createTreeView = True option).

Type:exhale.ExhaleNode
Param:node The node that we are setting the above information for.
generateSingleNodeRST(node)

Creates the reStructuredText document for the leaf like node object. This method should only be used with nodes in the following member lists:

  • self.class_like
  • self.enums
  • self.functions
  • self.typedefs
  • self.unions
  • self.variables
  • self.defines

File, directory, and namespace nodes are treated separately.

Parameters:
node (ExhaleNode)

The leaf like node being generated by this method.

generateNamespaceNodeDocuments()

Generates the reStructuredText document for every namespace, including nested namespaces that were removed from self.namespaces (but added as children to one of the namespaces in self.namespaces).

The documents generated do not use the Breathe namespace directive, but instead link to the relevant documents associated with this namespace.

generateSingleNamespace(nspace)

Helper method for exhale.ExhaleRoot.generateNamespaceNodeDocuments(). Writes the reStructuredText file for the given namespace.

Parameters:
nspace (ExhaleNode)

The namespace node to create the reStructuredText document for.

generateNamespaceChildrenString(nspace)

Helper method for exhale.ExhaleRoot.generateSingleNamespace(), and exhale.ExhaleRoot.generateFileNodeDocuments(). Builds the body text for the namespace node document that links to all of the child namespaces, structs, classes, functions, typedefs, unions, and variables associated with this namespace.

Parameters:
nspace (ExhaleNode)

The namespace node we are generating the body text for.

Return (str):

The string to be written to the namespace node’s reStructuredText document.

generateSortedChildListString(sectionTitle, previousString, lst)

Helper method for exhale.ExhaleRoot.generateNamespaceChildrenString(). Used to build up a continuous string with all of the children separated out into titled sections.

This generates a new titled section with sectionTitle and puts a link to every node found in lst in this section. The newly created section is appended to previousString and then returned.

TODO:

Change this to use string streams like the other methods instead.

Parameters:
sectionTitle (str)

The title of the section for this list of children.

previousString (str)

The string to append the newly created section to.

lst (list)

A list of ExhaleNode objects that are to be linked to from this section. This method sorts lst in place.

generateFileNodeDocuments()

Generates the reStructuredText documents for files as well as the file’s program listing reStructuredText document if applicable. Refer to Customizing File Pages for changing the output of this method. The remainder of the file lists all nodes that have been discovered to be defined (e.g. classes) or referred to (e.g. included files or files that include this file).

generateDirectoryNodeDocuments()

Generates all of the directory reStructuredText documents.

generateDirectoryNodeRST(node)

Helper method for exhale.ExhaleRoot.generateDirectoryNodeDocuments(). Generates the reStructuredText documents for the given directory node. Directory nodes will only link to files and subdirectories within it.

Parameters:
node (ExhaleNode)

The directory node to generate the reStructuredText document for.

generateAPIRootBody()

Generates the root library api file’s body text. The method calls exhale.ExhaleRoot.gerrymanderNodeFilenames() first to enable proper internal linkage between reStructuredText documents. Afterward, it calls exhale.ExhaleRoot.generateViewHierarchies() followed by exhale.ExhaleRoot.generateUnabridgedAPI() to generate both hierarchies as well as the full API listing. As a result, three files will now be ready:

  1. self.class_view_file
  2. self.directory_view_file
  3. self.unabridged_api_file

These three files are then included into the root library file. The consequence of using an include directive is that Sphinx will complain about these three files never being included in any toctree directive. These warnings are expected, and preferred to using a toctree because otherwise the user would have to click on the class view link from the toctree in order to see it. This behavior has been acceptable for me so far, but if it is causing you problems please raise an issue on GitHub and I may be able to conditionally use a toctree if you really need it.

gerrymanderNodeFilenames()

When creating nodes, the filename needs to be relative to conf.py, so it will include self.root_directory. However, when generating the API, the file we are writing to is in the same directory as the generated node files so we need to remove the directory path from a given ExhaleNode’s file_name before we can include it or use it in a toctree.

generateViewHierarchies()

Wrapper method to create the view hierarchies. Currently it just calls exhale.ExhaleRoot.generateClassView() and exhale.ExhaleRoot.generateDirectoryView() — if you want to implement additional hierarchies, implement the additionaly hierarchy method and call it from here. Then make sure to include it in exhale.ExhaleRoot.generateAPIRootBody().

generateClassView(treeView)

Generates the class view hierarchy, writing it to self.class_view_file.

Parameters:
treeView (bool)

Whether or not to use the collapsibleList version. See the createTreeView description in exhale.generate().

generateDirectoryView(treeView)

Generates the file view hierarchy, writing it to self.directory_view_file.

Parameters:
treeView (bool)

Whether or not to use the collapsibleList version. See the createTreeView description in exhale.generate().

generateUnabridgedAPI()

Generates the unabridged (full) API listing into self.unabridged_api_file. This is necessary as some items may not show up in either hierarchy view, depending on:

  1. The item. For example, if a namespace has only one member which is a variable, then neither the namespace nor the variable will be declared in the class view hierarchy. It will be present in the file page it was declared in but not on the main library page.
  2. The configurations of Doxygen. For example, see the warning in exhale.ExhaleRoot.fileRefDiscovery(). Items whose parents cannot be rediscovered withouth the programlisting will still be documented, their link appearing in the unabridged API listing.

Currently, the API is generated in the following (somewhat arbitrary) order:

  • Namespaces
  • Classes and Structs
  • Enums
  • Unions
  • Functions
  • Variables
  • Defines
  • Typedefs
  • Directories
  • Files

If you want to change the ordering, just change the order of the calls to exhale.ExhaleRoot.enumerateAll() in this method.

enumerateAll(subsectionTitle, lst, openFile)

Helper function for exhale.ExhaleRoot.generateUnabridgedAPI(). Simply writes a subsection to openFile (a toctree to the file_name) of each ExhaleNode in sorted(lst) if len(lst) > 0. Otherwise, nothing is written to the file.

Parameters:
subsectionTitle (str)

The title of this subsection, e.g. "Namespaces" or "Files".

lst (list)

The list of ExhaleNodes to be enumerated in this subsection.

openFile (File)

The already open file object to write to directly. No safety checks are performed, make sure this is a real file object that has not been closed already.

generateAPIRootSummary()

Writes the library API root summary to the main library file. See the documentation for the key afterBodySummary in exhale.generate().

toConsole()

Convenience function for printing out the entire API being generated to the console. Unused in the release, but is helpful for debugging ;)

consoleFormat(sectionTitle, lst)

Helper method for exhale.ExhaleRoot.toConsole(). Prints the given sectionTitle and calls exhale.ExhaleNode.toConsole() with 0 as the level for every ExhaleNode in lst.

Parameters:
sectionTitle (str)

The title that will be printed with some visual separators around it.

lst (list)

The list of ExhaleNodes to print to the console.