--- /dev/null
+# -*- coding: utf-8 -*-
+"""
+ sphinx.ext.coverage
+ ~~~~~~~~~~~~~~~~~~~
+
+ Check Python modules and C API for coverage. Mostly written by Josip
+ Dzolonga for the Google Highly Open Participation contest.
+
+ :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+import re
+import glob
+import inspect
+import cPickle as pickle
+from os import path
+
+from sphinx.builders import Builder
+
+
+# utility
+def write_header(f, text, char='-'):
+ f.write(text + '\n')
+ f.write(char * len(text) + '\n')
+
+def compile_regex_list(name, exps, warnfunc):
+ lst = []
+ for exp in exps:
+ try:
+ lst.append(re.compile(exp))
+ except Exception:
+ warnfunc('invalid regex %r in %s' % (exp, name))
+ return lst
+
+
+class CoverageBuilder(Builder):
+
+ name = 'coverage'
+
+ def init(self):
+ self.c_sourcefiles = []
+ for pattern in self.config.coverage_c_path:
+ pattern = path.join(self.srcdir, pattern)
+ self.c_sourcefiles.extend(glob.glob(pattern))
+
+ self.c_regexes = []
+ for (name, exp) in self.config.coverage_c_regexes.items():
+ try:
+ self.c_regexes.append((name, re.compile(exp)))
+ except Exception:
+ self.warn('invalid regex %r in coverage_c_regexes' % exp)
+
+ self.c_ignorexps = {}
+ for (name, exps) in self.config.coverage_ignore_c_items.iteritems():
+ self.c_ignorexps[name] = compile_regex_list(
+ 'coverage_ignore_c_items', exps, self.warn)
+ self.mod_ignorexps = compile_regex_list(
+ 'coverage_ignore_modules', self.config.coverage_ignore_modules,
+ self.warn)
+ self.cls_ignorexps = compile_regex_list(
+ 'coverage_ignore_classes', self.config.coverage_ignore_classes,
+ self.warn)
+ self.fun_ignorexps = compile_regex_list(
+ 'coverage_ignore_functions', self.config.coverage_ignore_functions,
+ self.warn)
+
+ def get_outdated_docs(self):
+ return 'coverage overview'
+
+ def write(self, *ignored):
+ self.py_undoc = {}
+ self.build_py_coverage()
+ self.write_py_coverage()
+
+ self.c_undoc = {}
+ self.build_c_coverage()
+ self.write_c_coverage()
+
+ def build_c_coverage(self):
+ # Fetch all the info from the header files
+ c_objects = self.env.domaindata['c']['objects']
+ for filename in self.c_sourcefiles:
+ undoc = []
+ f = open(filename, 'r')
+ try:
+ for line in f:
+ for key, regex in self.c_regexes:
+ match = regex.match(line)
+ if match:
+ name = match.groups()[0]
+ if name not in c_objects:
+ for exp in self.c_ignorexps.get(key, ()):
+ if exp.match(name):
+ break
+ else:
+ undoc.append((key, name))
+ continue
+ finally:
+ f.close()
+ if undoc:
+ self.c_undoc[filename] = undoc
+
+ def write_c_coverage(self):
+ output_file = path.join(self.outdir, 'c.txt')
+ op = open(output_file, 'w')
+ try:
+ if self.config.coverage_write_headline:
+ write_header(op, 'Undocumented C API elements', '=')
+ op.write('\n')
+
+ for filename, undoc in self.c_undoc.iteritems():
+ write_header(op, filename)
+ for typ, name in undoc:
+ op.write(' * %-50s [%9s]\n' % (name, typ))
+ op.write('\n')
+ finally:
+ op.close()
+
+ def build_py_coverage(self):
+ objects = self.env.domaindata['py']['objects']
+ modules = self.env.domaindata['py']['modules']
+
+ skip_undoc = self.config.coverage_skip_undoc_in_source
+
+ for mod_name in modules:
+ ignore = False
+ for exp in self.mod_ignorexps:
+ if exp.match(mod_name):
+ ignore = True
+ break
+ if ignore:
+ continue
+
+ try:
+ mod = __import__(mod_name, fromlist=['foo'])
+ except ImportError, err:
+ self.warn('module %s could not be imported: %s' %
+ (mod_name, err))
+ self.py_undoc[mod_name] = {'error': err}
+ continue
+
+ funcs = []
+ classes = {}
+
+ for name, obj in inspect.getmembers(mod):
+ # diverse module attributes are ignored:
+ if name[0] == '_':
+ # begins in an underscore
+ continue
+ if not hasattr(obj, '__module__'):
+ # cannot be attributed to a module
+ continue
+ if obj.__module__ != mod_name:
+ # is not defined in this module
+ continue
+
+ full_name = '%s.%s' % (mod_name, name)
+
+ if inspect.isfunction(obj):
+ if full_name not in objects:
+ for exp in self.fun_ignorexps:
+ if exp.match(name):
+ break
+ else:
+ if skip_undoc and not obj.__doc__:
+ continue
+ funcs.append(name)
+ elif inspect.isclass(obj):
+ for exp in self.cls_ignorexps:
+ if exp.match(name):
+ break
+ else:
+ if full_name not in objects:
+ if skip_undoc and not obj.__doc__:
+ continue
+ # not documented at all
+ classes[name] = []
+ continue
+
+ attrs = []
+
+ for attr_name in dir(obj):
+ if attr_name not in obj.__dict__:
+ continue
+ attr = getattr(obj, attr_name)
+ if not (inspect.ismethod(attr) or
+ inspect.isfunction(attr)):
+ continue
+ if attr_name[0] == '_':
+ # starts with an underscore, ignore it
+ continue
+ if skip_undoc and not attr.__doc__:
+ # skip methods without docstring if wished
+ continue
+
+ full_attr_name = '%s.%s' % (full_name, attr_name)
+ if full_attr_name not in objects:
+ attrs.append(attr_name)
+
+ if attrs:
+ # some attributes are undocumented
+ classes[name] = attrs
+
+ self.py_undoc[mod_name] = {'funcs': funcs, 'classes': classes}
+
+ def write_py_coverage(self):
+ output_file = path.join(self.outdir, 'python.txt')
+ op = open(output_file, 'w')
+ failed = []
+ try:
+ if self.config.coverage_write_headline:
+ write_header(op, 'Undocumented Python objects', '=')
+ keys = self.py_undoc.keys()
+ keys.sort()
+ for name in keys:
+ undoc = self.py_undoc[name]
+ if 'error' in undoc:
+ failed.append((name, undoc['error']))
+ else:
+ if not undoc['classes'] and not undoc['funcs']:
+ continue
+
+ write_header(op, name)
+ if undoc['funcs']:
+ op.write('Functions:\n')
+ op.writelines(' * %s\n' % x for x in undoc['funcs'])
+ op.write('\n')
+ if undoc['classes']:
+ op.write('Classes:\n')
+ for name, methods in sorted(undoc['classes'].iteritems()):
+ if not methods:
+ op.write(' * %s\n' % name)
+ else:
+ op.write(' * %s -- missing methods:\n' % name)
+ op.writelines(' - %s\n' % x for x in methods)
+ op.write('\n')
+
+ if failed:
+ write_header(op, 'Modules that failed to import')
+ op.writelines(' * %s -- %s\n' % x for x in failed)
+ finally:
+ op.close()
+
+ def finish(self):
+ # dump the coverage data to a pickle file too
+ picklepath = path.join(self.outdir, 'undoc.pickle')
+ dumpfile = open(picklepath, 'wb')
+ try:
+ pickle.dump((self.py_undoc, self.c_undoc), dumpfile)
+ finally:
+ dumpfile.close()
+
+
+def setup(app):
+ app.add_builder(CoverageBuilder)
+ app.add_config_value('coverage_ignore_modules', [], False)
+ app.add_config_value('coverage_ignore_functions', [], False)
+ app.add_config_value('coverage_ignore_classes', [], False)
+ app.add_config_value('coverage_c_path', [], False)
+ app.add_config_value('coverage_c_regexes', {}, False)
+ app.add_config_value('coverage_ignore_c_items', {}, False)
+ app.add_config_value('coverage_write_headline', True, False)
+ app.add_config_value('coverage_skip_undoc_in_source', False, False)
===============
.. automodule:: tornado.web
- :exclude-members: RequestHandler, Application, asynchronous, addslash, removeslash, URLSpec, url
Request handlers
----------------
.. autoclass:: RequestHandler
- :exclude-members: initialize, prepare, get, post, put, delete, head, options, get_argument, get_arguments, decode_argument, set_status, set_header, write, flush, finish, render, render_string, send_error, get_error_html, cookies, get_cookie, set_cookie, clear_cookie, clear_all_cookies, get_secure_cookie, set_secure_cookie, create_signed_value
**Entry points**
.. automethod:: finish
.. automethod:: render
.. automethod:: render_string
+ .. automethod:: redirect
.. automethod:: send_error
.. automethod:: get_error_html
+ .. automethod:: clear
+
**Cookies**
**Other**
+ .. automethod:: async_callback
+ .. automethod:: check_xsrf_cookie
+ .. automethod:: compute_etag
+ .. automethod:: get_browser_locale
+ .. automethod:: get_current_user
+ .. automethod:: get_login_url
+ .. automethod:: get_status
+ .. automethod:: get_template_path
+ .. automethod:: get_user_locale
+ .. automethod:: on_connection_close
+ .. automethod:: require_setting
+ .. automethod:: static_url
+ .. automethod:: xsrf_form_html
+
Application configuration
-----------------------------
.. autoclass:: Application
+ :members:
.. autoclass:: URLSpec
Everything else
---------------
+ .. autoexception:: HTTPError
+ .. autoclass:: UIModule
+ :members:
+
+ .. autoclass:: ErrorHandler
+ .. autoclass:: FallbackHandler
+ .. autoclass:: RedirectHandler
+ .. autoclass:: StaticFileHandler
+ :members: