From b399af06bc9177496b7b6f44d172b4d3df62c8e4 Mon Sep 17 00:00:00 2001 From: Abdelrahman Elbashandy Date: Thu, 11 Mar 2021 11:30:09 -0800 Subject: [PATCH] API documentation Created an API page Added in _static a collapsible-list library for tree generation of hierarchies Included a script that parses Doxygen XML files to generate pages for: 1. Alg, Core, Data, I/O 2. Class Hierarchy 3. File Hierarchy --- .gitignore | 2 + doc/rtd/_static/collapsible-lists/LICENSE.md | 7 + .../collapsible-lists/css/button-closed.png | Bin 0 -> 256 bytes .../collapsible-lists/css/button-open.png | Bin 0 -> 240 bytes .../_static/collapsible-lists/css/button.png | Bin 0 -> 230 bytes .../css/list-item-contents.png | Bin 0 -> 147 bytes .../css/list-item-last-open.png | Bin 0 -> 161 bytes .../collapsible-lists/css/list-item-last.png | Bin 0 -> 160 bytes .../collapsible-lists/css/list-item-open.png | Bin 0 -> 160 bytes .../collapsible-lists/css/list-item-root.png | Bin 0 -> 145 bytes .../collapsible-lists/css/list-item.png | Bin 0 -> 157 bytes .../collapsible-lists/css/tree_view.css | 61 +++ .../js/CollapsibleLists.compressed.js | 83 ++++ .../js/apply-collapsible-lists.js | 3 + doc/rtd/api/api.rst | 12 + doc/rtd/conf.py | 16 +- doc/rtd/index.rst | 1 + doc/rtd/parse_xml.py | 359 ++++++++++++++++++ 18 files changed, 538 insertions(+), 6 deletions(-) create mode 100644 doc/rtd/_static/collapsible-lists/LICENSE.md create mode 100644 doc/rtd/_static/collapsible-lists/css/button-closed.png create mode 100644 doc/rtd/_static/collapsible-lists/css/button-open.png create mode 100644 doc/rtd/_static/collapsible-lists/css/button.png create mode 100644 doc/rtd/_static/collapsible-lists/css/list-item-contents.png create mode 100644 doc/rtd/_static/collapsible-lists/css/list-item-last-open.png create mode 100644 doc/rtd/_static/collapsible-lists/css/list-item-last.png create mode 100644 doc/rtd/_static/collapsible-lists/css/list-item-open.png create mode 100644 doc/rtd/_static/collapsible-lists/css/list-item-root.png create mode 100644 doc/rtd/_static/collapsible-lists/css/list-item.png create mode 100644 doc/rtd/_static/collapsible-lists/css/tree_view.css create mode 100644 doc/rtd/_static/collapsible-lists/js/CollapsibleLists.compressed.js create mode 100644 doc/rtd/_static/collapsible-lists/js/apply-collapsible-lists.js create mode 100644 doc/rtd/api/api.rst create mode 100755 doc/rtd/parse_xml.py diff --git a/.gitignore b/.gitignore index ddcff675c..957306f03 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ _build *.pt *.vscode* +.DS_Store +generated_rtd* diff --git a/doc/rtd/_static/collapsible-lists/LICENSE.md b/doc/rtd/_static/collapsible-lists/LICENSE.md new file mode 100644 index 000000000..ef81a6453 --- /dev/null +++ b/doc/rtd/_static/collapsible-lists/LICENSE.md @@ -0,0 +1,7 @@ +This code is the fruit of Kate Morley's labor, taken from here: + +- http://code.iamkate.com/javascript/collapsible-lists/ + +She includes a generous CC0 1.0 license for all materials on her site: + +- http://code.iamkate.com/ diff --git a/doc/rtd/_static/collapsible-lists/css/button-closed.png b/doc/rtd/_static/collapsible-lists/css/button-closed.png new file mode 100644 index 0000000000000000000000000000000000000000..417eb2fc40d844946cb18f0966073d9549b2682d GIT binary patch literal 256 zcmeAS@N?(olHy`uVBq!ia0vp^+#t-s1|(OmDOUqhk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5X7J0fjhE&{YnRu4-h=M??`^DysoChD5DQRk`<~UBuW2qKc zziXdDcc-59hY!zd`yQXz^Ic!5%6zAqU-6V>n_mhrtlhfXuuURaI5PXG;W68mg4800 z-G-bOYuRTgKjzR_n)kX+IsWPo<0ApmnQQkS+m?HMM)ACd7Y{5Hj7qC3N#qpYl5P_0 zWxnG)w_L?GyGa5~OQuZTz%MUjB%e`n`M&%g4g-eh-O1-=TXk}Qu4V9a^>bP0l+XkK Dnpk0b literal 0 HcmV?d00001 diff --git a/doc/rtd/_static/collapsible-lists/css/button-open.png b/doc/rtd/_static/collapsible-lists/css/button-open.png new file mode 100644 index 0000000000000000000000000000000000000000..ac4a6ef32a50516609a06733d3365c78237e2143 GIT binary patch literal 240 zcmeAS@N?(olHy`uVBq!ia0vp^+#t-s1|(OmDOUqhk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5XCV9FzhE&{|GBJ>gS&_#j`GUT_;*XoNPsnBTUtm6Y&+UWI zzhh}p_Fm4rZ#T9-;BoF*cdbf!(e5A-HSIvY)bAY6=4_uLWcl2u=-kP@-`8&amZQa? zcbGwU|ALtpHI%;ip7~?-g8%3Cn;OS5n38#<|C#vBUf-h_aen=WPb~a4CH+tKE*EHG o{QhC0^XI-+?dA4A1QHnTT=Tf{X8(i9K-V#Ny85}Sb4q9e0Cgu}D*ylh literal 0 HcmV?d00001 diff --git a/doc/rtd/_static/collapsible-lists/css/button.png b/doc/rtd/_static/collapsible-lists/css/button.png new file mode 100644 index 0000000000000000000000000000000000000000..631d734d136a3c0e7698e249b09ac06462589ca8 GIT binary patch literal 230 zcmeAS@N?(olHy`uVBq!ia0vp^+#t-s1|(OmDOUqhk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5XIy_w*Ln>}_1wcZrxMOpdTT1SY*0BaajE)#RCaoBVu2L* zl`q`0TYJ;m{DmgIKFEJ*``x_5|FhF>RLskN_)_w^#h<=_&?6G!7R%4e%r2L^v-9u4 c=?u&a+cKO!dpZ{#2fB&D)78&qol`;+0OL4aGynhq literal 0 HcmV?d00001 diff --git a/doc/rtd/_static/collapsible-lists/css/list-item-contents.png b/doc/rtd/_static/collapsible-lists/css/list-item-contents.png new file mode 100644 index 0000000000000000000000000000000000000000..bc082929dccbabcf58e5e7d88abe49bcb21c191e GIT binary patch literal 147 zcmeAS@N?(olHy`uVBq!ia0vp^azHG>!3HGXX8P_2Qj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS>JicCFS978H@y*ay)lYxPQ`QU?pk5l&F=w6!exiSCJoJkpJ l*0<{;UuGVFgYVglYz$osB0q2a^8jQegQu&X%Q~loCIAKZH$VUY literal 0 HcmV?d00001 diff --git a/doc/rtd/_static/collapsible-lists/css/list-item-last-open.png b/doc/rtd/_static/collapsible-lists/css/list-item-last-open.png new file mode 100644 index 0000000000000000000000000000000000000000..cf4cf9bdb9027b5b50ce2e259e5c8248d08e4e28 GIT binary patch literal 161 zcmeAS@N?(olHy`uVBq!ia0vp^azHG>!3HGXX8P_2Qj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS>Jikv-N978H@CH?vT-=5j(#;#Irj|meS+Zs9(8xE{Ex>&3~ z$|mdMh0QZq`|td3+%RL}F}Z*Cvv#=Y%5AN<@@QeYp+f^BL(Mr3|LlYN!3HGXX8P_2Qj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS>Jikv)M978H@CH?vT-=5j(#;#Irj|meS+Zs9(8xE{Ex>&3~ z$|mdMh0QZq`|s38MV;wbJ4vGVabUN*uH4p&D@i#F3I`ZWpL2P7J1TSnO=IwM^>bP0 Hl+XkKgRnR! literal 0 HcmV?d00001 diff --git a/doc/rtd/_static/collapsible-lists/css/list-item-open.png b/doc/rtd/_static/collapsible-lists/css/list-item-open.png new file mode 100644 index 0000000000000000000000000000000000000000..0889c801a9a86ea0fdbbd8cb07e3f47885bfa33e GIT binary patch literal 160 zcmeAS@N?(olHy`uVBq!ia0vp^azHG>!3HGXX8P_2Qj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS>Jikv)M978H@CH?vT-=5j(#;#Irj|meS+Zs9(8xE{Ex>&3~ z$|mdMh0QZq`|td3+%#j_)Fb~d9x=`O2$JKs?Pg@+VW>I9;UCzqxBzGxgQu&X%Q~lo FCIHwyIzIpa literal 0 HcmV?d00001 diff --git a/doc/rtd/_static/collapsible-lists/css/list-item-root.png b/doc/rtd/_static/collapsible-lists/css/list-item-root.png new file mode 100644 index 0000000000000000000000000000000000000000..874417106af03875a02c3e19b1d57186419be94b GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0vp^azHG>!3HGXX8P_2Qj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS>Jii|y7978H@y}7{1%fP^Kctdl&_4V=;hZAWFPHJ_UW$Ci= p@bLU$*(Mvt36 literal 0 HcmV?d00001 diff --git a/doc/rtd/_static/collapsible-lists/css/list-item.png b/doc/rtd/_static/collapsible-lists/css/list-item.png new file mode 100644 index 0000000000000000000000000000000000000000..81934f9b82d482150215e2dbfd21b7a94802c1c7 GIT binary patch literal 157 zcmeAS@N?(olHy`uVBq!ia0vp^azHG>!3HGXX8P_2Qj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS>JitIgI978H@CH?vT-=5j(#;#Irj|meS+Zs9(8xE{Ex>&3~ z$|mdMh0QZq`|td3+*Gk;lEl`ED~|%Z-F4j<85r3Zj#;q>9G$xQ9MC8RPgg&ebxsLQ E0O;yB$N&HU literal 0 HcmV?d00001 diff --git a/doc/rtd/_static/collapsible-lists/css/tree_view.css b/doc/rtd/_static/collapsible-lists/css/tree_view.css new file mode 100644 index 000000000..fa21ac4e8 --- /dev/null +++ b/doc/rtd/_static/collapsible-lists/css/tree_view.css @@ -0,0 +1,61 @@ +/* Source taken directly from: + * view-source:http://code.iamkate.com/javascript/collapsible-lists/ + * + * Kate Morley's license for this code is CC0: + * Created by [Kate Morley](http://iamkate.com/). Except where explicitly + * stated otherwise, all content is released under the terms of the + * [CC0 1.0 Universal legal code](http://creativecommons.org/publicdomain/zero/1.0/legalcode). + */ +.treeView{ + -moz-user-select:none; + position:relative; +} + +.treeView ul{ + margin:0 0 0 -1.5em ! important; + padding:0 0 0 1.5em ! important; +} + +.treeView ul ul{ + background:url('list-item-contents.png') repeat-y left ! important; +} + +.treeView li.lastChild > ul{ + background-image:none ! important; +} + +.treeView li{ + margin:0 ! important; + padding:0 ! important; + background:url('list-item-root.png') no-repeat top left ! important; + list-style-position:inside ! important; + list-style-image:url('button.png') ! important; + cursor:auto; +} + +.treeView li.collapsibleListOpen{ + list-style-image:url('button-open.png') ! important; + cursor:pointer; +} + +.treeView li.collapsibleListClosed{ + list-style-image:url('button-closed.png') ! important; + cursor:pointer; +} + +.treeView li li{ + background-image:url('list-item.png') ! important; + padding-left:1.5em ! important; +} + +.treeView li.lastChild{ + background-image:url('list-item-last.png') ! important; +} + +.treeView li.collapsibleListOpen{ + background-image:url('list-item-open.png') ! important; +} + +.treeView li.collapsibleListOpen.lastChild{ + background-image:url('list-item-last-open.png') ! important; +} diff --git a/doc/rtd/_static/collapsible-lists/js/CollapsibleLists.compressed.js b/doc/rtd/_static/collapsible-lists/js/CollapsibleLists.compressed.js new file mode 100644 index 000000000..429406cf3 --- /dev/null +++ b/doc/rtd/_static/collapsible-lists/js/CollapsibleLists.compressed.js @@ -0,0 +1,83 @@ +/* + +CollapsibleLists.js + +An object allowing lists to dynamically expand and collapse + +Created by Kate Morley - http://code.iamkate.com/ - and released under +the terms of the CC0 1.0 Universal legal code: + +http://creativecommons.org/publicdomain/zero/1.0/legalcode + +*/ + +var CollapsibleLists=new function(){ +this.apply=function(_1){ +var _2=document.getElementsByTagName("ul"); +for(var _3=0;_3<_2.length;_3++){ +if(_2[_3].className.match(/(^| )collapsibleList( |$)/)){ +this.applyTo(_2[_3],true); +if(!_1){ +var _4=_2[_3].getElementsByTagName("ul"); +for(var _5=0;_5<_4.length;_5++){ +_4[_5].className+=" collapsibleList"; +} +} +} +} +}; +this.applyTo=function(_6,_7){ +var _8=_6.getElementsByTagName("li"); +for(var _9=0;_9<_8.length;_9++){ +if(!_7||_6==_8[_9].parentNode){ +if(_8[_9].addEventListener){ +_8[_9].addEventListener("mousedown",function(e){ +e.preventDefault(); +},false); +}else{ +_8[_9].attachEvent("onselectstart",function(){ +event.returnValue=false; +}); +} +if(_8[_9].addEventListener){ +_8[_9].addEventListener("click",_a(_8[_9]),false); +}else{ +_8[_9].attachEvent("onclick",_a(_8[_9])); +} +_b(_8[_9]); +} +} +}; +function _a(_c){ +return function(e){ +if(!e){ +e=window.event; +} +var _d=(e.target?e.target:e.srcElement); +while(_d.nodeName!="LI"){ +_d=_d.parentNode; +} +if(_d==_c){ +_b(_c); +} +}; +}; +function _b(_e){ +var _f=_e.className.match(/(^| )collapsibleListClosed( |$)/); +var uls=_e.getElementsByTagName("ul"); +for(var _10=0;_100){ +_e.className+=" collapsibleList"+(_f?"Open":"Closed"); +} +}; +}(); + diff --git a/doc/rtd/_static/collapsible-lists/js/apply-collapsible-lists.js b/doc/rtd/_static/collapsible-lists/js/apply-collapsible-lists.js new file mode 100644 index 000000000..e848bb981 --- /dev/null +++ b/doc/rtd/_static/collapsible-lists/js/apply-collapsible-lists.js @@ -0,0 +1,3 @@ +$(document).ready(function() { + CollapsibleLists.apply(); +}); diff --git a/doc/rtd/api/api.rst b/doc/rtd/api/api.rst new file mode 100644 index 000000000..854360cbe --- /dev/null +++ b/doc/rtd/api/api.rst @@ -0,0 +1,12 @@ + +API +=== + +TECA provides an extensive suite of algorithms and software utilities +to build Climate Data Analysis/Transformation pipelines. + +.. include:: generated_rtd_pages.rst + +.. include:: ../_build/rst/generated_rtd_class_hierarchy.rst + +.. include:: ../_build/rst/generated_rtd_file_hierarchy.rst diff --git a/doc/rtd/conf.py b/doc/rtd/conf.py index cf04d7855..f46ebf1a1 100644 --- a/doc/rtd/conf.py +++ b/doc/rtd/conf.py @@ -31,6 +31,7 @@ if not os.path.exists('_build/html'): os.makedirs('_build/html') subprocess.call('doxygen', shell=True) + subprocess.call('./parse_xml.py', shell=True) # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom @@ -63,13 +64,16 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -#html_static_path = ['_static'] html_static_path = ['_static'] -html_context = { - 'css_files': [ - '_static/theme_overrides.css', # overrides for wide tables in RTD theme - ], - } +html_css_files = [ + 'theme_overrides.css', # overrides for wide tables in RTD theme + 'collapsible-lists/css/tree_view.css' + ] + +html_js_files = [ + 'collapsible-lists/js/CollapsibleLists.compressed.js', + 'collapsible-lists/js/apply-collapsible-lists.js' + ] numfig = True diff --git a/doc/rtd/index.rst b/doc/rtd/index.rst index 169816980..5caf756b1 100644 --- a/doc/rtd/index.rst +++ b/doc/rtd/index.rst @@ -22,4 +22,5 @@ to develop new diagnostics. applications python developer + api/api bibliography diff --git a/doc/rtd/parse_xml.py b/doc/rtd/parse_xml.py new file mode 100755 index 000000000..0a5500c7a --- /dev/null +++ b/doc/rtd/parse_xml.py @@ -0,0 +1,359 @@ +#!/usr/bin/env python3 + +import os +import xml.etree.ElementTree as ET +from collections import defaultdict + + +class TECA_Tree(object): + def __init__( + self, xml_dir='_build/xml', + index_file='index.xml', kinds=['class']): + """Construct TECA ('class' for now) Tree + + :param index_file: Doxygen's index.xml path + :type index_file: str + """ + self.index_file = index_file + self.xml_dir = xml_dir + self.kinds = kinds + + xml_tree = ET.parse(os.path.join(xml_dir, index_file)) + self.xml_root = xml_tree.getroot() + + self.nodes = defaultdict(None) + self.directory_structure = None + + self.meta_info = { + 'alg': { + 'full_name': 'Algorithms', + 'description': 'TECA\'s suite of algorithms that can \ + be inserted in functional pipelines' + }, + 'core': { + 'full_name': 'Core', + 'description': 'TECA\'s core components' + }, + 'data': { + 'full_name': 'Data', + 'description': 'TECA\'s data structures' + }, + 'io': { + 'full_name': 'I/O', + 'description': 'TECA\'s I/O components to read datasets \ + efficiently' + } + } + + self.get_components() + + self.generate_file_hierarchy() + + self.rescue_every_family() + self.generate_class_hierarchy() + + self.generate_api_pages(output_dir='api') + + def get_first_dir(self, trunk_dict): + for key, _ in trunk_dict.items(): + if key != 'files': + return key + + def get_compound_refid(self, name, kind='file'): + for teca_element in self.xml_root.findall('compound'): + if teca_element.get('kind') == kind: + if name == teca_element.find('name').text: + return teca_element.get('refid') + + def get_components(self): + for teca_element in self.xml_root.findall('compound'): + kind = teca_element.get('kind') + if kind in self.kinds: + name = teca_element.find('name').text + if '::' not in name: + node = self.Node( + teca_element.get('refid'), + name, + self.xml_dir + ) + + if node.location: + self.nodes[teca_element.get('refid')] = node + + def rescue_every_family(self): + for node_refid, node in self.nodes.items(): + node.find_family(self.nodes) + + self.nodes[node_refid] = node + + def generate_class_hierarchy(self, output_dir='_build/rst'): + def structure_class_hierarchy( + node, element_type='Class', lastChild=False): + html = '' + if lastChild: + html += '
  • ' + else: + html += '
  • ' + + html += element_type + ' ' + html += node.name + '' + + if node.children: + html += '
      ' + children_len_minus_one = len(node.children) - 1 + for i, child_node in enumerate(node.children): + if i == children_len_minus_one: + html += structure_class_hierarchy( + child_node, lastChild=True) + else: + html += structure_class_hierarchy(child_node) + html += '
    ' + html += '
  • ' + return html + + rst = '\nClass Hierarchy\n---------------\n\n.. raw:: html\n\n ' + + html = '
      ' + html += '
      • ' + + root_nodes = [] + for _, node in self.nodes.items(): + if node.parent is None and ('::' not in node.name): + root_nodes.append(node) + + for i, root_node in enumerate(root_nodes): + if i == len(root_nodes) - 1: + html += structure_class_hierarchy(root_node, lastChild=True) + else: + html += structure_class_hierarchy(root_node) + + html += '
    ' + + rst += html + '\n\n.. end raw html for treeView\n' + + if not os.path.exists(output_dir): + os.makedirs(output_dir) + + with open(os.path.join( + output_dir, 'generated_rtd_class_hierarchy.rst'), + 'w') as f: + f.write(rst) + + def generate_file_hierarchy(self, output_dir='_build/rst'): + def structure_file_hierarchy(name, trunk, lastChild=False): + html = '' + if lastChild: + html += '
  • ' + else: + html += '
  • ' + + html += name + + trunk_len_minus_one = len(trunk.items()) - 1 + for i, (key, value) in enumerate(trunk.items()): + html += '
      ' + + if key == 'files': + files_len_minus_one = len(value) - 1 + for j, file in enumerate(value): + if j == files_len_minus_one: + html += '
    • ' + else: + html += '
    • ' + html += '' + html += file[0] + '' + html += '
    • ' + else: + if i == trunk_len_minus_one: + html += structure_file_hierarchy( + key, trunk[key], lastChild=True) + else: + html += structure_file_hierarchy(key, trunk[key]) + html += '
    ' + html += '
  • ' + + return html + + trunk = defaultdict(dict, (('files', []),)) + + def attach(location, trunk, refid): + parts = location.split('/', 1) + if len(parts) == 1: # branch is a file + trunk['files'].append(( + parts[0], + refid, + self.get_compound_refid(parts[0]) + '_source') + ) + else: + directory, others = parts + if directory not in trunk: + trunk[directory] = defaultdict(dict, (('files', []),)) + attach(others, trunk[directory], refid) + + rst = '\nFile Hierarchy\n---------------\n\n.. raw:: html\n\n ' + + html = '
      ' + html += '
      • ' + + for _, node in self.nodes.items(): + attach(node.location, trunk, node.refid) + + trunk['TECA'] = trunk.pop(self.get_first_dir(trunk)) + self.directory_structure = trunk + + first_dir = 'TECA' + html += structure_file_hierarchy( + first_dir, trunk[first_dir], lastChild=True) + + html += '
    ' + + rst += html + '\n\n.. end raw html for treeView\n' + + if not os.path.exists(output_dir): + os.makedirs(output_dir) + + with open(os.path.join( + output_dir, 'generated_rtd_file_hierarchy.rst'), + 'w') as f: + f.write(rst) + + def generate_api_pages(self, output_dir='_build/rst'): + first_dir = 'TECA' + trunk = self.directory_structure[first_dir] + + if not os.path.exists(output_dir): + os.makedirs(output_dir) + + generated_files = [] + + for key, value in trunk.items(): + if key == 'files': + continue + + page_name = self.meta_info[key]['full_name'] + + rst = '' + rst += '\n.. _' + page_name + ':\n' + rst += '\n' + page_name + '\n' + rst += '-' * len(page_name) + '\n\n' + rst += self.meta_info[key]['description'] + '\n\n' + + rst += '.. csv-table:: TECA Classes\n' + rst += ' :header: "Class", "Description"\n' + rst += ' :widths: 5, 30\n\n' + + for _, refid, _ in value['files']: + node = self.nodes[refid] + + rst += ' ' + node.name + '_ , ' + + if (node.brief_description and + not node.brief_description.isspace()): + rst += node.brief_description.strip() + + rst += '\n' + + rst += '\n' + for _, refid, _ in value['files']: + node = self.nodes[refid] + + rst += '.. _' + node.name + ': ' + node.refid + '.html\n' + + filename = 'generated_rtd_%s.rst' % key + with open(os.path.join(output_dir, filename), 'w') as f: + f.write(rst) + + generated_files.append( + (filename, self.meta_info[key]['full_name'])) + + rst = '\n\n.. toctree::\n :maxdepth: 1\n :caption: Contents:\n\n' + + for file, full_name in generated_files: + rst += ' ' + full_name + '<' + file.replace('.rst', '') + '>\n' + + with open(os.path.join( + output_dir, 'generated_rtd_pages.rst'), + 'w') as f: + f.write(rst) + + class Node: + def __init__(self, refid, name, xml_dir): + self.refid = refid + self.name = name + + self.xml_dir = xml_dir + + self.location = None + + self.brief_description = None + + self.parent = None + self.children = [] + self.found_family = False + + self.node_xml_root = None + + self._construct_xml_root() + self.find_location() + self.find_brief_description() + + def _construct_xml_root(self): + node_xml_tree = ET.parse( + os.path.join(self.xml_dir, self.refid + '.xml')) + + node_xml_root = node_xml_tree.getroot() + self.node_xml_root = node_xml_root.find('compounddef') + + def find_location(self, avoids=['.cxx']): + if self.node_xml_root is None: + raise ValueError("The Node's xml tree root has to be set!") + + location = self.node_xml_root.find('location') + if location is not None: + location = location.get('file') + for txt in avoids: + if txt in location: + return + self.location = location + + def find_brief_description(self): + if self.node_xml_root is None: + raise ValueError("The Node's xml tree root has to be set!") + + briefdescription = self.node_xml_root.find('briefdescription') + + brief_description = "" + for text in briefdescription.itertext(): + brief_description += text + + self.brief_description = brief_description + + def find_family(self, nodes): + if self.found_family: + return + + if self.node_xml_root is None: + raise ValueError("The Node's xml tree root has to be set!") + + parent = self.node_xml_root.find('basecompoundref') + if parent is not None and 'refid' in parent.attrib: + self.parent = nodes[parent.get('refid')] + + children = [] + for child_element in self.node_xml_root.findall( + 'derivedcompoundref'): + if 'refid' in child_element.attrib: + child = nodes[child_element.get('refid')] + children.append(child) + + self.children = children + + self.found_family = True + + +def main(): + teca_tree = TECA_Tree() + + +if __name__ == '__main__': + main()