# -*- coding: utf-8 -*- """ Sphinx Auto-API """ import os import sys import yaml import fnmatch from collections import defaultdict import traceback from sphinx.util.osutil import ensuredir from jinja2 import Environment, FileSystemLoader from .utils import TEMPLATE_DIR from epyparse import parsed env = Environment(loader=FileSystemLoader(TEMPLATE_DIR)) class DotNetMember(object): def __init__(self, obj): self.obj = obj def render(self): print "Unknown Type: %s (%s)" % (self.obj['type'], self.obj['name']) self.obj['underline'] = len(self.obj['qualifiedName']['CSharp']) * "~" template = env.get_template('member.rst') return template.render(**self.obj) class PythonMember(object): def __init__(self, obj): self.obj = obj def render(self): print "Unknown Type: %s (%s)" % (self.obj['type'], self.obj['fullname']) self.obj['underline'] = len(self.obj['fullname']) * "~" template = env.get_template('python/member.rst') try: return template.render(**self.obj) except Exception, e: print "Exception, Keeping going" print sys.exc_info() return '' class PythonFunction(object): def __init__(self, obj): self.obj = obj def render(self): # print "Rendering function %s" % self.obj['fullname'] self.obj['underline'] = len(self.obj['fullname']) * "~" template = env.get_template('python/function.rst') try: return template.render(**self.obj) except Exception, e: print "Exception, Keeping going" print sys.exc_info() return '' class PythonModule(object): def __init__(self, obj): self.obj = obj self.item_map = defaultdict(list) self.sort() def sort(self): for item in self.obj.get('children', []): if 'type' not in item: print "Missing Type: %s" % item continue self.item_map[item['type']].append(classify(item, 'python')) def render(self): # print "Rendering module %s" % self.obj['fullname'] self.obj['underline'] = len(self.obj['fullname']) * "#" template = env.get_template('python/module.rst') ctx = self.obj ctx.update(dict( methods=self.item_map['function'], classes=self.item_map['class'], imports=self.obj['imports'], )) return template.render(**ctx) class PythonClass(object): def __init__(self, obj): self.obj = obj self.item_map = defaultdict(list) self.sort() def sort(self): for item in self.obj.get('children', []): if 'type' not in item: print "Missing Type: %s" % item continue self.item_map[item['type']].append(classify(item, 'python')) def render(self, indent=4): # print "Rendering class %s" % self.obj['fullname'] template = env.get_template('python/class.rst') ctx = self.obj ctx.update(dict( underline=len(self.obj['fullname']) * "-", methods=self.item_map['function'], classes=self.item_map['class'], indent=indent, )) return template.render(**ctx) class DotNetClass(object): def __init__(self, obj): self.obj = obj self.item_map = defaultdict(list) self.sort() def sort(self): for item in self.obj['items']: if 'type' not in item: print "Missing Type: %s" % item continue self.item_map[item['type']].append(item) def render(self, indent=4): # print "Rendering class %s" % self.obj['name'] self.obj['underline'] = len(self.obj['qualifiedName']['CSharp']) * "#" template = env.get_template('class.rst') ctx = self.obj ctx.update(dict( ctors=self.item_map['Constructor'], methods=self.item_map['Method'], attributes=self.item_map['Property'], )) return template.render(**ctx) def classify(obj, obj_type): if 'type' not in obj: return '' if obj_type == 'python': if obj['type'] == 'module': if not obj.get('children'): return '' return PythonModule(obj) if obj['type'] == 'class': return PythonClass(obj) if obj['type'] == 'function': return PythonFunction(obj) else: return PythonMember(obj) if obj_type == 'dotnet': if obj['type'] == 'Class': return DotNetClass(obj) if obj['type'] == 'Namespace': return '' # for now else: return DotNetMember(obj) def parse(obj, obj_type): cls = classify(obj, obj_type) if cls: return cls.render() def ignore_file(app, filename): for pat in app.config.autoapi_ignore: if fnmatch.fnmatch(filename, pat): return True return False def load_yaml(app): if not app.config.autoapi_dir: return app.env.autoapi_data = [] if app.config.autoapi_type == 'dotnet': for _file in os.listdir(app.config.autoapi_dir): # print "Loading Yaml from %s" % _file to_open = os.path.join(app.env.config.autoapi_dir, _file) app.env.autoapi_data.append(yaml.safe_load(open(to_open, 'r'))) # Generate RST for obj in app.env.autoapi_data: # print "Parsing %s" % obj['name'] rst = parse(obj, 'dotnet') if rst: path = os.path.join(app.config.autoapi_root, '%s%s' % (obj['name']['CSharp'], app.config.source_suffix[0])) ensuredir(app.config.autoapi_root) with open(path, 'w+') as fp: fp.write(rst) elif app.config.autoapi_type == 'python': for root, dirnames, filenames in os.walk(app.config.autoapi_dir): for filename in fnmatch.filter(filenames, u'*.py'): to_open = os.path.join(root, filename) if ignore_file(app, to_open): continue # print "Parsing Python File from %s" % to_open try: parsed_data = parsed(to_open) app.env.autoapi_data.append(parsed_data) except Exception, e: print "Exception, Keeping going: %s" % to_open print sys.exc_info() import traceback; traceback.print_exc(); app.env.autoapi_enabled = True # Generate RST for obj in app.env.autoapi_data: # print "Parsing %s" % obj['fullname'] rst = parse(obj, 'python') if rst: path = os.path.join(app.config.autoapi_root, '%s%s' % (obj['fullname'], app.config.source_suffix[0])) ensuredir(app.config.autoapi_root) with open(path, 'w+') as fp: fp.write(rst.encode('utf8')) def doctree_read(app, doctree): pass # para = nodes.paragraph('Test Para', 'Test Para') # new_doc = utils.new_document(para) def env_updated(app, env): # env.found_docs.add(os.path.join(app.config.autoapi_root, 'test')) pass def collect_pages(app): pass context = { 'title': 'Test Title', 'body': 'Fak', } yield (os.path.join(app.config.autoapi_root, 'test_insert'), context, 'page.html') def setup(app): app.connect('doctree-read', doctree_read) app.connect('builder-inited', load_yaml) app.connect('env-updated', env_updated) app.connect('html-collect-pages', collect_pages) app.add_config_value('autoapi_type', 'dotnet', 'html') app.add_config_value('autoapi_root', 'autoapi', 'html') app.add_config_value('autoapi_ignore', ['*migrations*'], 'html') app.add_config_value('autoapi_dir', '', 'html')