diff --git a/ext_libs/Scripts/pdoc b/ext_libs/Scripts/pdoc
new file mode 100644
index 000000000..1a3a5454f
--- /dev/null
+++ b/ext_libs/Scripts/pdoc
@@ -0,0 +1,506 @@
+#!c:\osgeo4~1\bin\python3.exe
+
+from __future__ import absolute_import, division, print_function
+import argparse
+try:
+ from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
+except ImportError:
+ from http.server import BaseHTTPRequestHandler, HTTPServer
+import codecs
+import datetime
+import imp
+import os
+import os.path as path
+import pkgutil
+import re
+import subprocess
+import sys
+import tempfile
+
+import pdoc
+
+# `xrange` is `range` with Python3.
+try:
+ xrange = xrange
+except NameError:
+ xrange = range
+
+version_suffix = '%d.%d' % (sys.version_info[0], sys.version_info[1])
+default_http_dir = path.join(tempfile.gettempdir(), 'pdoc-%s' % version_suffix)
+
+parser = argparse.ArgumentParser(
+ description='Automatically generate API docs for Python modules.',
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+aa = parser.add_argument
+aa('module_name', type=str, nargs='?',
+ help='The Python module name. This may be an import path resolvable in '
+ 'the current environment, or a file path to a Python module or '
+ 'package.')
+aa('ident_name', type=str, nargs='?',
+ help='When specified, only identifiers containing the name given '
+ 'will be shown in the output. Search is case sensitive. '
+ 'Has no effect when --http is set.')
+aa('--version', action='store_true',
+ help='Print the version of pdoc and exit.')
+aa('--html', action='store_true',
+ help='When set, the output will be HTML formatted.')
+aa('--html-dir', type=str, default='.',
+ help='The directory to output HTML files to. This option is ignored when '
+ 'outputting documentation as plain text.')
+aa('--html-no-source', action='store_true',
+ help='When set, source code will not be viewable in the generated HTML. '
+ 'This can speed up the time required to document large modules.')
+aa('--overwrite', action='store_true',
+ help='Overwrites any existing HTML files instead of producing an error.')
+aa('--all-submodules', action='store_true',
+ help='When set, every submodule will be included, regardless of whether '
+ '__all__ is set and contains the submodule.')
+aa('--external-links', action='store_true',
+ help='When set, identifiers to external modules are turned into links. '
+ 'This is automatically set when using --http.')
+aa('--template-dir', type=str, default=None,
+ help='Specify a directory containing Mako templates. '
+ 'Alternatively, put your templates in $XDG_CONFIG_HOME/pdoc and '
+ 'pdoc will automatically find them.')
+aa('--link-prefix', type=str, default='',
+ help='A prefix to use for every link in the generated documentation. '
+ 'No link prefix results in all links being relative. '
+ 'Has no effect when combined with --http.')
+aa('--only-pypath', action='store_true',
+ help='When set, only modules in your PYTHONPATH will be documented.')
+aa('--http', action='store_true',
+ help='When set, pdoc will run as an HTTP server providing documentation '
+ 'of all installed modules. Only modules found in PYTHONPATH will be '
+ 'listed.')
+aa('--http-dir', type=str, default=default_http_dir,
+ help='The directory to cache HTML documentation when running as an HTTP '
+ 'server.')
+aa('--http-host', type=str, default='localhost',
+ help='The host on which to run the HTTP server.')
+aa('--http-port', type=int, default=8080,
+ help='The port on which to run the HTTP server.')
+aa('--http-html', action='store_true',
+ help='Internal use only. Do not set.')
+args = parser.parse_args()
+
+
+class WebDoc (BaseHTTPRequestHandler):
+ def do_HEAD(self):
+ if self.path != '/':
+ out = self.html()
+ if out is None:
+ self.send_response(404)
+ self.end_headers()
+ return
+
+ self.send_response(200)
+ self.send_header('Content-type', 'text/html')
+ self.end_headers()
+
+ def do_GET(self):
+ if self.path == '/':
+ modules = []
+ for (imp, name, ispkg) in pkgutil.iter_modules(pdoc.import_path):
+ if name == 'setup' and not ispkg:
+ continue
+ modules.append((name, quick_desc(imp, name, ispkg)))
+ modules = sorted(modules, key=lambda x: x[0].lower())
+
+ out = pdoc.tpl_lookup.get_template('/html.mako')
+ out = out.render(modules=modules, link_prefix=args.link_prefix)
+ out = out.strip()
+ elif self.path.endswith('.ext'):
+ # External links are a bit weird. You should view them as a giant
+ # hack. Basically, the idea is to "guess" where something lives
+ # when documenting another module and hope that guess can actually
+ # track something down in a more global context.
+ #
+ # The idea here is to start specific by looking for HTML that
+ # exists that matches the full external path given. Then trim off
+ # one component at the end and try again.
+ #
+ # If no HTML is found, then we ask `pdoc` to do its thang on the
+ # parent module in the external path. If all goes well, that
+ # module will then be able to find the external identifier.
+
+ import_path = self.path[:-4].lstrip('/')
+ resolved = self.resolve_ext(import_path)
+ if resolved is None: # Try to generate the HTML...
+ _eprint('Generating HTML for %s on the fly...' % import_path)
+ try:
+ process_html_out(import_path.split('.')[0])
+ except subprocess.CalledProcessError as e:
+ _eprint('Could not run "%s" (exit code: %d): %s' %
+ (' '.join(e.cmd), e.returncode, e.output))
+
+ # Try looking once more.
+ resolved = self.resolve_ext(import_path)
+ if resolved is None: # All hope is lost.
+ self.send_response(404)
+ self.send_header('Content-type', 'text/html')
+ self.end_headers()
+ self.echo('External identifier %s
not found.'
+ % import_path)
+ return
+ self.send_response(302)
+ self.send_header('Location', resolved)
+ self.end_headers()
+ return
+ else:
+ out = self.html()
+ if out is None:
+ self.send_response(404)
+ self.send_header('Content-type', 'text/html')
+ self.end_headers()
+
+ err = 'Module %s
not found.' % self.import_path
+ self.echo(err)
+ return
+
+ self.send_response(200)
+ self.send_header('Content-type', 'text/html')
+ self.end_headers()
+ self.echo(out)
+
+ def echo(self, s):
+ self.wfile.write(s.encode('utf-8'))
+
+ def html(self):
+ """
+ Retrieves and sends the HTML belonging to the path given in
+ URL. This method is smart and will look for HTML files already
+ generated and account for whether they are stale compared to
+ the source code.
+ """
+
+ # Deny favico shortcut early.
+ if self.path == '/favicon.ico':
+ return None
+
+ # Look for the module file without importing it.
+ impath = self.import_path
+ try:
+ mfile = pkgutil.get_loader(self.import_path).get_filename()
+ except Exception as e:
+ _eprint('Could not load %s: %s' % (impath, e))
+ mfile = None
+
+ # Check the file system first before trying an import.
+ fp = self.file_path
+ if last_modified(mfile) < last_modified(fp) and os.access(fp, os.R_OK):
+ with codecs.open(fp, 'r', 'utf-8') as f:
+ return f.read()
+
+ # Regenerate the HTML by shelling out to pdoc.
+ # This ensures that the documentation is generated from a fresh import.
+ _eprint('Generating HTML for %s' % impath)
+ try:
+ process_html_out(impath)
+ except subprocess.CalledProcessError as e:
+ _eprint('Could not run "%s" (exit code: %d): %s' %
+ (' '.join(e.cmd), e.returncode, e.output))
+ return None
+
+ with codecs.open(self.file_path, 'r', 'utf-8') as f:
+ return f.read()
+
+ def resolve_ext(self, import_path):
+ def exists(p):
+ p = path.join(args.html_dir, p)
+ pkg = path.join(p, pdoc.html_package_name)
+ mod = p + pdoc.html_module_suffix
+
+ if path.isfile(pkg):
+ return pkg[len(args.html_dir):]
+ elif path.isfile(mod):
+ return mod[len(args.html_dir):]
+ return None
+
+ parts = import_path.split('.')
+ for i in xrange(len(parts), 0, -1):
+ p = path.join(*parts[0:i])
+ realp = exists(p)
+ if realp is not None:
+ return '/%s#%s' % (realp.lstrip('/'), import_path)
+ return None
+
+ @property
+ def file_path(self):
+ fp = path.join(args.html_dir, *self.import_path.split('.'))
+ pkgp = path.join(fp, pdoc.html_package_name)
+ if path.isdir(fp) and path.isfile(pkgp):
+ fp = pkgp
+ else:
+ fp += pdoc.html_module_suffix
+ return fp
+
+ @property
+ def import_path(self):
+ pieces = self.clean_path.split('/')
+ if pieces[-1].startswith(pdoc.html_package_name):
+ pieces = pieces[:-1]
+ if pieces[-1].endswith(pdoc.html_module_suffix):
+ pieces[-1] = pieces[-1][:-len(pdoc.html_module_suffix)]
+ return '.'.join(pieces)
+
+ @property
+ def clean_path(self):
+ new, _ = re.subn('//+', '/', self.path)
+ if '#' in new:
+ new = new[0:new.index('#')]
+ return new.strip('/')
+
+ def address_string(self):
+ return '%s:%s' % (self.client_address[0], self.client_address[1])
+
+
+def quick_desc(imp, name, ispkg):
+ if not hasattr(imp, 'path'):
+ # See issue #7.
+ return ''
+
+ if ispkg:
+ fp = path.join(imp.path, name, '__init__.py')
+ else:
+ fp = path.join(imp.path, '%s.py' % name)
+ if os.path.isfile(fp):
+ with codecs.open(fp, 'r', 'utf-8') as f:
+ quotes = None
+ doco = []
+ for i, line in enumerate(f):
+ if i == 0:
+ if len(line) >= 3 and line[0:3] in ("'''", '"""'):
+ quotes = line[0:3]
+ line = line[3:]
+ else:
+ break
+ line = line.rstrip()
+ if line.endswith(quotes):
+ doco.append(line[0:-3])
+ break
+ else:
+ doco.append(line)
+ desc = '\n'.join(doco)
+ if len(desc) > 200:
+ desc = desc[0:200] + '...'
+ return desc
+ return ''
+
+
+def _eprint(*args, **kwargs):
+ kwargs['file'] = sys.stderr
+ print(*args, **kwargs)
+
+
+def last_modified(fp):
+ try:
+ return datetime.datetime.fromtimestamp(os.stat(fp).st_mtime)
+ except:
+ return datetime.datetime.min
+
+
+def module_file(m):
+ mbase = path.join(args.html_dir, *m.name.split('.'))
+ if m.is_package():
+ return path.join(mbase, pdoc.html_package_name)
+ else:
+ return '%s%s' % (mbase, pdoc.html_module_suffix)
+
+
+def quit_if_exists(m):
+ def check_file(f):
+ if os.access(f, os.R_OK):
+ _eprint('%s already exists. Delete it or run with --overwrite' % f)
+ sys.exit(1)
+
+ if args.overwrite:
+ return
+ f = module_file(m)
+ check_file(f)
+
+ # If this is a package, make sure the package directory doesn't exist
+ # either.
+ if m.is_package():
+ check_file(path.dirname(f))
+
+
+def html_out(m, html=True):
+ f = module_file(m)
+ if not html:
+ f = module_file(m).replace(".html", ".md")
+ dirpath = path.dirname(f)
+ if not os.access(dirpath, os.R_OK):
+ os.makedirs(dirpath)
+ try:
+ with codecs.open(f, 'w+', 'utf-8') as w:
+ if not html:
+ out = m.text()
+ else:
+ out = m.html(external_links=args.external_links,
+ link_prefix=args.link_prefix,
+ http_server=args.http_html,
+ source=not args.html_no_source)
+ print(out, file=w)
+ except Exception:
+ try:
+ os.unlink(f)
+ except:
+ pass
+ raise
+ for submodule in m.submodules():
+ html_out(submodule, html)
+
+
+def process_html_out(impath):
+ # This unfortunate kludge is the only reasonable way I could think of
+ # to support reloading of modules. It's just too difficult to get
+ # modules to reload in the same process.
+
+ cmd = [sys.executable,
+ path.realpath(__file__),
+ '--html',
+ '--html-dir', args.html_dir,
+ '--http-html',
+ '--overwrite',
+ '--link-prefix', args.link_prefix]
+ if args.external_links:
+ cmd.append('--external-links')
+ if args.all_submodules:
+ cmd.append('--all-submodules')
+ if args.only_pypath:
+ cmd.append('--only-pypath')
+ if args.html_no_source:
+ cmd.append('--html-no-source')
+ if args.template_dir:
+ cmd.append('--template-dir')
+ cmd.append(args.template_dir)
+ cmd.append(impath)
+
+ # Can we make a good faith attempt to support 2.6?
+ # YES WE CAN!
+ p = subprocess.Popen(cmd, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ out = p.communicate()[0].strip().decode('utf-8')
+ if p.returncode > 0:
+ err = subprocess.CalledProcessError(p.returncode, cmd)
+ err.output = out
+ raise err
+ if len(out) > 0:
+ print(out)
+
+
+if __name__ == '__main__':
+ if args.version:
+ print(pdoc.__version__)
+ sys.exit(0)
+
+ # We close stdin because some modules, upon import, are not very polite
+ # and block on stdin.
+ try:
+ sys.stdin.close()
+ except:
+ pass
+
+ if not args.http and args.module_name is None:
+ _eprint('No module name specified.')
+ sys.exit(1)
+ if args.template_dir is not None:
+ pdoc.tpl_lookup.directories.insert(0, args.template_dir)
+ if args.http:
+ args.html = True
+ args.external_links = True
+ args.html_dir = args.http_dir
+ args.overwrite = True
+ args.link_prefix = '/'
+
+ # If PYTHONPATH is set, let it override everything if we want it to.
+ pypath = os.getenv('PYTHONPATH')
+ if args.only_pypath and pypath is not None and len(pypath) > 0:
+ pdoc.import_path = pypath.split(path.pathsep)
+
+ if args.http:
+ if args.module_name is not None:
+ _eprint('Module names cannot be given with --http set.')
+ sys.exit(1)
+
+ # Run the HTTP server.
+ httpd = HTTPServer((args.http_host, args.http_port), WebDoc)
+ print('pdoc server ready at http://%s:%d'
+ % (args.http_host, args.http_port), file=sys.stderr)
+
+ httpd.serve_forever()
+ httpd.server_close()
+ sys.exit(0)
+
+ docfilter = None
+ if args.ident_name and len(args.ident_name.strip()) > 0:
+ search = args.ident_name.strip()
+
+ def docfilter(o):
+ rname = o.refname
+ if rname.find(search) > -1 or search.find(o.name) > -1:
+ return True
+ if isinstance(o, pdoc.Class):
+ return search in o.doc or search in o.doc_init
+ return False
+
+ # Try to do a real import first. I think it's better to prefer
+ # import paths over files. If a file is really necessary, then
+ # specify the absolute path, which is guaranteed not to be a
+ # Python import path.
+ try:
+ module = pdoc.import_module(args.module_name)
+ except Exception as e:
+ module = None
+
+ # Get the module that we're documenting. Accommodate for import paths,
+ # files and directories.
+ if module is None:
+ isdir = path.isdir(args.module_name)
+ isfile = path.isfile(args.module_name)
+ if isdir or isfile:
+ fp = path.realpath(args.module_name)
+ module_name = path.basename(fp)
+ if isdir:
+ fp = path.join(fp, '__init__.py')
+ else:
+ module_name, _ = path.splitext(module_name)
+
+ # Use a special module name to avoid import conflicts.
+ # It is hidden from view via the `Module` class.
+ with open(fp) as f:
+ module = imp.load_source('__pdoc_file_module__', fp, f)
+ if isdir:
+ module.__path__ = [path.realpath(args.module_name)]
+ module.__pdoc_module_name = module_name
+ else:
+ module = pdoc.import_module(args.module_name)
+ module = pdoc.Module(module, docfilter=docfilter,
+ allsubmodules=args.all_submodules)
+
+ # Plain text?
+ if not args.html and not args.all_submodules:
+ output = module.text()
+ try:
+ print(output)
+ except IOError as e:
+ # This seems to happen for long documentation.
+ # This is obviously a hack. What's the real cause? Dunno.
+ if e.errno == 32:
+ pass
+ else:
+ raise e
+ sys.exit(0)
+
+ # HTML output depends on whether the module being documented is a package
+ # or not. If not, then output is written to {MODULE_NAME}.html in
+ # `html-dir`. If it is a package, then a directory called {MODULE_NAME}
+ # is created, and output is written to {MODULE_NAME}/index.html.
+ # Submodules are written to {MODULE_NAME}/{MODULE_NAME}.m.html and
+ # subpackages are written to {MODULE_NAME}/{MODULE_NAME}/index.html. And
+ # so on... The same rules apply for `http_dir` when `pdoc` is run as an
+ # HTTP server.
+ if not args.http:
+ quit_if_exists(module)
+ html_out(module, args.html)
+ sys.exit(0)
diff --git a/ext_libs/pdoc/__init__.py b/ext_libs/pdoc/__init__.py
new file mode 100644
index 000000000..7353bb7f6
--- /dev/null
+++ b/ext_libs/pdoc/__init__.py
@@ -0,0 +1,1206 @@
+"""
+Module pdoc provides types and functions for accessing the public
+documentation of a Python module. This includes modules (and
+sub-modules), functions, classes and module, class and instance
+variables. Docstrings are taken from modules, functions and classes
+using the special `__doc__` attribute. Docstrings for variables are
+extracted by examining the module's abstract syntax tree.
+
+The public interface of a module is determined through one of two
+ways. If `__all__` is defined in the module, then all identifiers in
+that list will be considered public. No other identifiers will be
+considered as public. Conversely, if `__all__` is not defined, then
+`pdoc` will heuristically determine the public interface. There are
+three rules that are applied to each identifier in the module:
+
+1. If the name starts with an underscore, it is **not** public.
+
+2. If the name is defined in a different module, it is **not** public.
+
+3. If the name refers to an immediate sub-module, then it is public.
+
+Once documentation for a module is created with `pdoc.Module`, it
+can be output as either HTML or plain text using the covenience
+functions `pdoc.html` and `pdoc.text`, or the corresponding methods
+`pdoc.Module.html` and `pdoc.Module.text`.
+
+Alternatively, you may run an HTTP server with the `pdoc` script
+included with this module.
+
+
+Compatibility
+-------------
+`pdoc` has been tested on Python 2.6, 2.7 and 3.3. It seems to work
+on all three.
+
+
+Contributing
+------------
+`pdoc` [is on GitHub](https://github.com/BurntSushi/pdoc). Pull
+requests and bug reports are welcome.
+
+
+Linking to other identifiers
+----------------------------
+In your documentation, you may link to other identifiers in
+your module or submodules. Linking is automatically done for
+you whenever you surround an identifier with a back quote
+(grave). The identifier name must be fully qualified. For
+example, \`pdoc.Doc.docstring\`
is correct while
+\`Doc.docstring\`
is incorrect.
+
+If the `pdoc` script is used to run an HTTP server, then external
+linking to other packages installed is possible. No extra work is
+necessary; simply use the fully qualified path. For example,
+\`nflvid.slice\`
will create a link to the `nflvid.slice`
+function, which is **not** a part of `pdoc` at all.
+
+
+Where does pdoc get documentation from?
+---------------------------------------
+Broadly speaking, `pdoc` gets everything you see from introspecting the
+module. This includes words describing a particular module, class,
+function or variable. While `pdoc` does some analysis on the source
+code of a module, importing the module itself is necessary to use
+Python's introspection features.
+
+In Python, objects like modules, functions, classes and methods have
+a special attribute named `__doc__` which contains that object's
+*docstring*. The docstring comes from a special placement of a string
+in your source code. For example, the following code shows how to
+define a function with a docstring and access the contents of that
+docstring:
+
+ #!python
+ >>> def test():
+ ... '''This is a docstring.'''
+ ... pass
+ ...
+ >>> test.__doc__
+ 'This is a docstring.'
+
+Something similar can be done for classes and modules too. For classes,
+the docstring should come on the line immediately following `class
+...`. For modules, the docstring should start on the first line of
+the file. These docstrings are what you see for each module, class,
+function and method listed in the documentation produced by `pdoc`.
+
+The above just about covers *standard* uses of docstrings in Python.
+`pdoc` extends the above in a few important ways.
+
+
+### Special docstring conventions used by `pdoc`
+
+**Firstly**, docstrings can be inherited. Consider the following code
+sample:
+
+ #!python
+ >>> class A (object):
+ ... def test():
+ ... '''Docstring for A.'''
+ ...
+ >>> class B (A):
+ ... def test():
+ ... pass
+ ...
+ >>> print(A.test.__doc__)
+ Docstring for A.
+ >>> print(B.test.__doc__)
+ None
+
+In Python, the docstring for `B.test` is empty, even though one was
+defined in `A.test`. If `pdoc` generates documentation for the above
+code, then it will automatically attach the docstring for `A.test` to
+`B.test` only if `B.test` does not have a docstring. In the default
+HTML output, an inherited docstring is grey.
+
+**Secondly**, docstrings can be attached to variables, which includes
+module (or global) variables, class variables and instance variables.
+Python by itself [does not allow docstrings to be attached to
+variables](http://www.python.org/dev/peps/pep-0224). For example:
+
+ #!python
+ variable = "SomeValue"
+ '''Docstring for variable.'''
+
+The resulting `variable` will have no `__doc__` attribute. To
+compensate, `pdoc` will read the source code when it's available to
+infer a connection between a variable and a docstring. The connection
+is only made when an assignment statement is followed by a docstring.
+
+Something similar is done for instance variables as well. By
+convention, instance variables are initialized in a class's `__init__`
+method. Therefore, `pdoc` adheres to that convention and looks for
+docstrings of variables like so:
+
+ #!python
+ def __init__(self):
+ self.variable = "SomeValue"
+ '''Docstring for instance variable.'''
+
+Note that `pdoc` only considers attributes defined on `self` as
+instance variables.
+
+Class and instance variables can also have inherited docstrings.
+
+**Thirdly and finally**, docstrings can be overridden with a special
+`__pdoc__` dictionary that `pdoc` inspects if it exists. The keys of
+`__pdoc__` should be identifiers within the scope of the module. (In
+the case of an instance variable `self.variable` for class `A`, its
+module identifier would be `A.variable`.) The values of `__pdoc__`
+should be docstrings.
+
+This particular feature is useful when there's no feasible way of
+attaching a docstring to something. A good example of this is a
+[namedtuple](http://goo.gl/akfXJ9):
+
+ #!python
+ __pdoc__ = {}
+
+ Table = namedtuple('Table', ['types', 'names', 'rows'])
+ __pdoc__['Table.types'] = 'Types for each column in the table.'
+ __pdoc__['Table.names'] = 'The names of each column in the table.'
+ __pdoc__['Table.rows'] = 'Lists corresponding to each row in the table.'
+
+`pdoc` will then show `Table` as a class with documentation for the
+`types`, `names` and `rows` members.
+
+Note that assignments to `__pdoc__` need to placed where they'll be
+executed when the module is imported. For example, at the top level
+of a module or in the definition of a class.
+
+If `__pdoc__[key] = None`, then `key` will not be included in the
+public interface of the module.
+
+
+License
+-------
+`pdoc` is in the public domain via the
+[UNLICENSE](http://unlicense.org).
+"""
+from __future__ import absolute_import, division, print_function
+import ast
+import imp
+import inspect
+import os
+import os.path as path
+import pkgutil
+import re
+import sys
+
+from mako.lookup import TemplateLookup
+from mako.exceptions import TopLevelLookupException
+
+__version__ = '0.3.2'
+"""
+The current version of pdoc. This value is read from `setup.py`.
+"""
+
+html_module_suffix = '.m.html'
+"""
+The suffix to use for module HTML files. By default, this is set to
+`.m.html`, where the extra `.m` is used to differentiate a package's
+`index.html` from a submodule called `index`.
+"""
+
+html_package_name = 'index.html'
+"""
+The file name to use for a package's `__init__.py` module.
+"""
+
+import_path = sys.path[:]
+"""
+A list of paths to restrict imports to. Any module that cannot be
+found in `import_path` will not be imported. By default, it is set to a
+copy of `sys.path` at initialization.
+"""
+
+_template_path = [
+ path.join(path.dirname(__file__), 'templates'),
+]
+"""
+A list of paths to search for Mako templates used to produce the
+plain text and HTML output. Each path is tried until a template is
+found.
+"""
+if os.getenv('XDG_CONFIG_HOME'):
+ _template_path.insert(0, path.join(os.getenv('XDG_CONFIG_HOME'), 'pdoc'))
+
+__pdoc__ = {}
+tpl_lookup = TemplateLookup(directories=_template_path,
+ cache_args={'cached': True,
+ 'cache_type': 'memory'})
+"""
+A `mako.lookup.TemplateLookup` object that knows how to load templates
+from the file system. You may add additional paths by modifying the
+object's `directories` attribute.
+"""
+
+
+def html(module_name, docfilter=None, allsubmodules=False,
+ external_links=False, link_prefix='', source=True):
+ """
+ Returns the documentation for the module `module_name` in HTML
+ format. The module must be importable.
+
+ `docfilter` is an optional predicate that controls which
+ documentation objects are shown in the output. It is a single
+ argument function that takes a documentation object and returns
+ `True` or `False`. If `False`, that object will not be included in
+ the output.
+
+ If `allsubmodules` is `True`, then every submodule of this module
+ that can be found will be included in the documentation, regardless
+ of whether `__all__` contains it.
+
+ If `external_links` is `True`, then identifiers to external modules
+ are always turned into links.
+
+ If `link_prefix` is `True`, then all links will have that prefix.
+ Otherwise, links are always relative.
+
+ If `source` is `True`, then source code will be retrieved for
+ every Python object whenever possible. This can dramatically
+ decrease performance when documenting large modules.
+ """
+ mod = Module(import_module(module_name),
+ docfilter=docfilter,
+ allsubmodules=allsubmodules)
+ return mod.html(external_links=external_links,
+ link_prefix=link_prefix, source=source)
+
+
+def text(module_name, docfilter=None, allsubmodules=False):
+ """
+ Returns the documentation for the module `module_name` in plain
+ text format. The module must be importable.
+
+ `docfilter` is an optional predicate that controls which
+ documentation objects are shown in the output. It is a single
+ argument function that takes a documentation object and returns
+ True of False. If False, that object will not be included in the
+ output.
+
+ If `allsubmodules` is `True`, then every submodule of this module
+ that can be found will be included in the documentation, regardless
+ of whether `__all__` contains it.
+ """
+ mod = Module(import_module(module_name),
+ docfilter=docfilter,
+ allsubmodules=allsubmodules)
+ return mod.text()
+
+
+def import_module(module_name):
+ """
+ Imports a module. A single point of truth for importing modules to
+ be documented by `pdoc`. In particular, it makes sure that the top
+ module in `module_name` can be imported by using only the paths in
+ `pdoc.import_path`.
+
+ If a module has already been imported, then its corresponding entry
+ in `sys.modules` is returned. This means that modules that have
+ changed on disk cannot be re-imported in the same process and have
+ its documentation updated.
+ """
+ if import_path != sys.path:
+ # Such a kludge. Only restrict imports if the `import_path` has
+ # been changed. We don't want to always restrict imports, since
+ # providing a path to `imp.find_module` stops it from searching
+ # in special locations for built ins or frozen modules.
+ #
+ # The problem here is that this relies on the `sys.path` not being
+ # independently changed since the initialization of this module.
+ # If it is changed, then some packages may fail.
+ #
+ # Any other options available?
+
+ # Raises an exception if the parent module cannot be imported.
+ # This hopefully ensures that we only explicitly import modules
+ # contained in `pdoc.import_path`.
+ imp.find_module(module_name.split('.')[0], import_path)
+
+ if module_name in sys.modules:
+ return sys.modules[module_name]
+ else:
+ __import__(module_name)
+ return sys.modules[module_name]
+
+
+def _source(obj):
+ """
+ Returns the source code of the Python object `obj` as a list of
+ lines. This tries to extract the source from the special
+ `__wrapped__` attribute if it exists. Otherwise, it falls back
+ to `inspect.getsourcelines`.
+
+ If neither works, then the empty list is returned.
+ """
+ try:
+ return inspect.getsourcelines(obj.__wrapped__)[0]
+ except:
+ pass
+ try:
+ return inspect.getsourcelines(obj)[0]
+ except:
+ return []
+
+
+def _get_tpl(name):
+ """
+ Returns the Mako template with the given name. If the template
+ cannot be found, a nicer error message is displayed.
+ """
+ try:
+ t = tpl_lookup.get_template(name)
+ except TopLevelLookupException:
+ locs = [path.join(p, name.lstrip('/')) for p in _template_path]
+ raise IOError(2, 'No template at any of: %s' % ', '.join(locs))
+ return t
+
+
+def _eprint(*args, **kwargs):
+ """Print to stderr."""
+ kwargs['file'] = sys.stderr
+ print(*args, **kwargs)
+
+
+def _safe_import(module_name):
+ """
+ A function for safely importing `module_name`, where errors are
+ suppressed and `stdout` and `stderr` are redirected to a null
+ device. The obligation is on the caller to close `stdin` in order
+ to avoid impolite modules from blocking on `stdin` when imported.
+ """
+ class _Null (object):
+ def write(self, *_):
+ pass
+
+ sout, serr = sys.stdout, sys.stderr
+ sys.stdout, sys.stderr = _Null(), _Null()
+ try:
+ m = import_module(module_name)
+ except:
+ m = None
+ sys.stdout, sys.stderr = sout, serr
+ return m
+
+
+def _var_docstrings(tree, module, cls=None, init=False):
+ """
+ Extracts variable docstrings given `tree` as the abstract syntax,
+ `module` as a `pdoc.Module` containing `tree` and an option `cls`
+ as a `pdoc.Class` corresponding to the tree. In particular, `cls`
+ should be specified when extracting docstrings from a class or an
+ `__init__` method. Finally, `init` should be `True` when searching
+ the AST of an `__init__` method so that `_var_docstrings` will only
+ accept variables starting with `self.` as instance variables.
+
+ A dictionary mapping variable name to a `pdoc.Variable` object is
+ returned.
+ """
+ vs = {}
+ children = list(ast.iter_child_nodes(tree))
+ for i, child in enumerate(children):
+ if isinstance(child, ast.Assign) and len(child.targets) == 1:
+ if not init and isinstance(child.targets[0], ast.Name):
+ name = child.targets[0].id
+ elif (isinstance(child.targets[0], ast.Attribute)
+ and isinstance(child.targets[0].value, ast.Name)
+ and child.targets[0].value.id == 'self'):
+ name = child.targets[0].attr
+ else:
+ continue
+ if not _is_exported(name) \
+ and name not in getattr(module, '__all__', []):
+ continue
+
+ docstring = ''
+ if (i+1 < len(children)
+ and isinstance(children[i+1], ast.Expr)
+ and isinstance(children[i+1].value, ast.Str)):
+ docstring = children[i+1].value.s
+
+ vs[name] = Variable(name, module, docstring, cls=cls)
+ return vs
+
+
+def _is_exported(ident_name):
+ """
+ Returns `True` if `ident_name` matches the export criteria for an
+ identifier name.
+
+ This should not be used by clients. Instead, use
+ `pdoc.Module.is_public`.
+ """
+ return not ident_name.startswith('_')
+
+
+class Doc (object):
+ """
+ A base class for all documentation objects.
+
+ A documentation object corresponds to *something* in a Python module
+ that has a docstring associated with it. Typically, this only includes
+ modules, classes, functions and methods. However, `pdoc` adds support
+ for extracting docstrings from the abstract syntax tree, which means
+ that variables (module, class or instance) are supported too.
+
+ A special type of documentation object `pdoc.External` is used to
+ represent identifiers that are not part of the public interface of
+ a module. (The name "External" is a bit of a misnomer, since it can
+ also correspond to unexported members of the module, particularly in
+ a class's ancestor list.)
+ """
+ def __init__(self, name, module, docstring):
+ """
+ Initializes a documentation object, where `name` is the public
+ identifier name, `module` is a `pdoc.Module` object, and
+ `docstring` is a string containing the docstring for `name`.
+ """
+ self.module = module
+ """
+ The module documentation object that this object was defined
+ in.
+ """
+
+ self.name = name
+ """
+ The identifier name for this object.
+ """
+
+ self.docstring = inspect.cleandoc(docstring or '')
+ """
+ The docstring for this object. It has already been cleaned
+ by `inspect.cleandoc`.
+ """
+
+ @property
+ def source(self):
+ """
+ Returns the source code of the Python object `obj` as a list of
+ lines. This tries to extract the source from the special
+ `__wrapped__` attribute if it exists. Otherwise, it falls back
+ to `inspect.getsourcelines`.
+
+ If neither works, then the empty list is returned.
+ """
+ assert False, 'subclass responsibility'
+
+ @property
+ def refname(self):
+ """
+ Returns an appropriate reference name for this documentation
+ object. Usually this is its fully qualified path. Every
+ documentation object must provide this property.
+
+ e.g., The refname for this property is
+ pdoc.Doc.refname
.
+ """
+ assert False, 'subclass responsibility'
+
+ def __lt__(self, other):
+ return self.name < other.name
+
+ def is_empty(self):
+ """
+ Returns true if the docstring for this object is empty.
+ """
+ return len(self.docstring.strip()) == 0
+
+
+class Module (Doc):
+ """
+ Representation of a module's documentation.
+ """
+
+ __pdoc__['Module.module'] = 'The Python module object.'
+ __pdoc__['Module.name'] = \
+ """
+ The name of this module with respect to the context in which
+ it was imported. It is always an absolute import path.
+ """
+
+ def __init__(self, module, docfilter=None, allsubmodules=False):
+ """
+ Creates a `Module` documentation object given the actual
+ module Python object.
+
+ `docfilter` is an optional predicate that controls which
+ documentation objects are returned in the following
+ methods: `pdoc.Module.classes`, `pdoc.Module.functions`,
+ `pdoc.Module.variables` and `pdoc.Module.submodules`. The
+ filter is propagated to the analogous methods on a `pdoc.Class`
+ object.
+
+ If `allsubmodules` is `True`, then every submodule of this
+ module that can be found will be included in the
+ documentation, regardless of whether `__all__` contains it.
+ """
+ name = getattr(module, '__pdoc_module_name', module.__name__)
+ super(Module, self).__init__(name, module, inspect.getdoc(module))
+
+ self._filtering = docfilter is not None
+ self._docfilter = (lambda _: True) if docfilter is None else docfilter
+ self._allsubmodules = allsubmodules
+
+ self.doc = {}
+ """A mapping from identifier name to a documentation object."""
+
+ self.refdoc = {}
+ """
+ The same as `pdoc.Module.doc`, but maps fully qualified
+ identifier names to documentation objects.
+ """
+
+ vardocs = {}
+ try:
+ tree = ast.parse(inspect.getsource(self.module))
+ vardocs = _var_docstrings(tree, self, cls=None)
+ except:
+ pass
+ self._declared_variables = vardocs.keys()
+
+ public = self.__public_objs()
+ for name, obj in public.items():
+ # Skip any identifiers that already have doco.
+ if name in self.doc and not self.doc[name].is_empty():
+ continue
+
+ # Functions and some weird builtins?, plus methods, classes,
+ # modules and module level variables.
+ if inspect.isfunction(obj) or inspect.isbuiltin(obj):
+ self.doc[name] = Function(name, self, obj)
+ elif inspect.ismethod(obj):
+ self.doc[name] = Function(name, self, obj)
+ elif inspect.isclass(obj):
+ self.doc[name] = Class(name, self, obj)
+ elif inspect.ismodule(obj):
+ # Only document modules that are submodules or are forcefully
+ # exported by __all__.
+ if obj is not self.module and \
+ (self.__is_exported(name, obj)
+ or self.is_submodule(obj.__name__)):
+ self.doc[name] = self.__new_submodule(name, obj)
+ elif name in vardocs:
+ self.doc[name] = vardocs[name]
+ else:
+ # Catch all for variables.
+ self.doc[name] = Variable(name, self, '', cls=None)
+
+ # Now scan the directory if this is a package for all modules.
+ if not hasattr(self.module, '__path__') \
+ and not hasattr(self.module, '__file__'):
+ pkgdir = []
+ else:
+ pkgdir = getattr(self.module, '__path__',
+ [path.dirname(self.module.__file__)])
+ if self.is_package():
+ for (_, root, _) in pkgutil.iter_modules(pkgdir):
+ # Ignore if this module was already doc'd.
+ if root in self.doc:
+ continue
+
+ # Ignore if it isn't exported, unless we've specifically
+ # requested to document all submodules.
+ if not self._allsubmodules \
+ and not self.__is_exported(root, self.module):
+ continue
+
+ fullname = '%s.%s' % (self.name, root)
+ m = _safe_import(fullname)
+ if m is None:
+ continue
+ self.doc[root] = self.__new_submodule(root, m)
+
+ # Now see if we can grab inheritance relationships between classes.
+ for docobj in self.doc.values():
+ if isinstance(docobj, Class):
+ docobj._fill_inheritance()
+
+ # Build the reference name dictionary.
+ for basename, docobj in self.doc.items():
+ self.refdoc[docobj.refname] = docobj
+ if isinstance(docobj, Class):
+ for v in docobj.class_variables():
+ self.refdoc[v.refname] = v
+ for v in docobj.instance_variables():
+ self.refdoc[v.refname] = v
+ for f in docobj.methods():
+ self.refdoc[f.refname] = f
+ for f in docobj.functions():
+ self.refdoc[f.refname] = f
+
+ # Finally look for more docstrings in the __pdoc__ override.
+ for name, docstring in getattr(self.module, '__pdoc__', {}).items():
+ refname = '%s.%s' % (self.refname, name)
+ if docstring is None:
+ self.doc.pop(name, None)
+ self.refdoc.pop(refname, None)
+ continue
+
+ dobj = self.find_ident(refname)
+ if isinstance(dobj, External):
+ continue
+ dobj.docstring = inspect.cleandoc(docstring)
+
+ def text(self):
+ """
+ Returns the documentation for this module as plain text.
+ """
+ t = _get_tpl('/text.mako')
+ text, _ = re.subn('\n\n\n+', '\n\n', t.render(module=self).strip())
+ return text
+
+ def html(self, external_links=False, link_prefix='',
+ source=True, **kwargs):
+ """
+ Returns the documentation for this module as
+ self-contained HTML.
+
+ If `external_links` is `True`, then identifiers to external
+ modules are always turned into links.
+
+ If `link_prefix` is `True`, then all links will have that
+ prefix. Otherwise, links are always relative.
+
+ If `source` is `True`, then source code will be retrieved for
+ every Python object whenever possible. This can dramatically
+ decrease performance when documenting large modules.
+
+ `kwargs` is passed to the `mako` render function.
+ """
+ t = _get_tpl('/html.mako')
+ t = t.render(module=self,
+ external_links=external_links,
+ link_prefix=link_prefix,
+ show_source_code=source,
+ **kwargs)
+ return t.strip()
+
+ def is_package(self):
+ """
+ Returns `True` if this module is a package.
+
+ Works by checking if `__package__` is not `None` and whether it
+ has the `__path__` attribute.
+ """
+ return hasattr(self.module, '__path__')
+
+ @property
+ def source(self):
+ return _source(self.module)
+
+ @property
+ def refname(self):
+ return self.name
+
+ def mro(self, cls):
+ """
+ Returns a method resolution list of documentation objects
+ for `cls`, which must be a documentation object.
+
+ The list will contain objects belonging to `pdoc.Class` or
+ `pdoc.External`. Objects belonging to the former are exported
+ classes either in this module or in one of its sub-modules.
+ """
+ ups = inspect.getmro(cls.cls)
+ return list(map(lambda c: self.find_class(c), ups))
+
+ def descendents(self, cls):
+ """
+ Returns a descendent list of documentation objects for `cls`,
+ which must be a documentation object.
+
+ The list will contain objects belonging to `pdoc.Class` or
+ `pdoc.External`. Objects belonging to the former are exported
+ classes either in this module or in one of its sub-modules.
+ """
+ if cls.cls == type or not hasattr(cls.cls, '__subclasses__'):
+ # Is this right?
+ return []
+
+ downs = cls.cls.__subclasses__()
+ return list(map(lambda c: self.find_class(c), downs))
+
+ def is_public(self, name):
+ """
+ Returns `True` if and only if an identifier with name `name` is
+ part of the public interface of this module. While the names
+ of sub-modules are included, identifiers only exported by
+ sub-modules are not checked.
+
+ `name` should be a fully qualified name, e.g.,
+ pdoc.Module.is_public
.
+ """
+ return name in self.refdoc
+
+ def find_class(self, cls):
+ """
+ Given a Python `cls` object, try to find it in this module
+ or in any of the exported identifiers of the submodules.
+ """
+ for doc_cls in self.classes():
+ if cls is doc_cls.cls:
+ return doc_cls
+ for module in self.submodules():
+ doc_cls = module.find_class(cls)
+ if not isinstance(doc_cls, External):
+ return doc_cls
+ return External('%s.%s' % (cls.__module__, cls.__name__))
+
+ def find_ident(self, name):
+ """
+ Searches this module and **all** of its sub-modules for an
+ identifier with name `name` in its list of exported
+ identifiers according to `pdoc`. Note that unexported
+ sub-modules are searched.
+
+ A bare identifier (without `.` separators) will only be checked
+ for in this module.
+
+ The documentation object corresponding to the identifier is
+ returned. If one cannot be found, then an instance of
+ `External` is returned populated with the given identifier.
+ """
+ if name in self.refdoc:
+ return self.refdoc[name]
+ for module in self.submodules():
+ o = module.find_ident(name)
+ if not isinstance(o, External):
+ return o
+ return External(name)
+
+ def variables(self):
+ """
+ Returns all documented module level variables in the module
+ sorted alphabetically as a list of `pdoc.Variable`.
+ """
+ p = lambda o: isinstance(o, Variable) and self._docfilter(o)
+ return sorted(filter(p, self.doc.values()))
+
+ def classes(self):
+ """
+ Returns all documented module level classes in the module
+ sorted alphabetically as a list of `pdoc.Class`.
+ """
+ p = lambda o: isinstance(o, Class) and self._docfilter(o)
+ return sorted(filter(p, self.doc.values()))
+
+ def functions(self):
+ """
+ Returns all documented module level functions in the module
+ sorted alphabetically as a list of `pdoc.Function`.
+ """
+ p = lambda o: isinstance(o, Function) and self._docfilter(o)
+ return sorted(filter(p, self.doc.values()))
+
+ def submodules(self):
+ """
+ Returns all documented sub-modules in the module sorted
+ alphabetically as a list of `pdoc.Module`.
+ """
+ p = lambda o: isinstance(o, Module) and self._docfilter(o)
+ return sorted(filter(p, self.doc.values()))
+
+ def is_submodule(self, name):
+ """
+ Returns `True` if and only if `name` starts with the full
+ import path of `self` and has length at least one greater than
+ `len(self.name)`.
+ """
+ return self.name != name and name.startswith(self.name)
+
+ def __is_exported(self, name, module):
+ """
+ Returns `True` if and only if `pdoc` considers `name` to be
+ a public identifier for this module where `name` was defined
+ in the Python module `module`.
+
+ If this module has an `__all__` attribute, then `name` is
+ considered to be exported if and only if it is a member of
+ this module's `__all__` list.
+
+ If `__all__` is not set, then whether `name` is exported or
+ not is heuristically determined. Firstly, if `name` starts
+ with an underscore, it will not be considered exported.
+ Secondly, if `name` was defined in a module other than this
+ one, it will not be considered exported. In all other cases,
+ `name` will be considered exported.
+ """
+ if hasattr(self.module, '__all__'):
+ return name in self.module.__all__
+ if not _is_exported(name):
+ return False
+ if module is not None and self.module.__name__ != module.__name__:
+ return name in self._declared_variables
+ return True
+
+ def __public_objs(self):
+ """
+ Returns a dictionary mapping a public identifier name to a
+ Python object.
+ """
+ members = dict(inspect.getmembers(self.module))
+ return dict([(name, obj)
+ for name, obj in members.items()
+ if self.__is_exported(name, inspect.getmodule(obj))])
+
+ def __new_submodule(self, name, obj):
+ """
+ Create a new submodule documentation object for this `obj`,
+ which must by a Python module object and pass along any
+ settings in this module.
+ """
+ # Forcefully set the module name so that it is always the absolute
+ # import path. We can't rely on `obj.__name__`, since it doesn't
+ # necessarily correspond to the public exported name of the module.
+ obj.__dict__['__pdoc_module_name'] = '%s.%s' % (self.refname, name)
+ return Module(obj,
+ docfilter=self._docfilter,
+ allsubmodules=self._allsubmodules)
+
+
+class Class (Doc):
+ """
+ Representation of a class's documentation.
+ """
+
+ def __init__(self, name, module, class_obj):
+ """
+ Same as `pdoc.Doc.__init__`, except `class_obj` must be a
+ Python class object. The docstring is gathered automatically.
+ """
+ super(Class, self).__init__(name, module, inspect.getdoc(class_obj))
+
+ self.cls = class_obj
+ """The class Python object."""
+
+ self.doc = {}
+ """A mapping from identifier name to a `pdoc.Doc` objects."""
+
+ self.doc_init = {}
+ """
+ A special version of `pdoc.Class.doc` that contains
+ documentation for instance variables found in the `__init__`
+ method.
+ """
+
+ public = self.__public_objs()
+ try:
+ # First try and find docstrings for class variables.
+ # Then move on to finding docstrings for instance variables.
+ # This must be optional, since not all modules have source
+ # code available.
+ cls_ast = ast.parse(inspect.getsource(self.cls)).body[0]
+ self.doc = _var_docstrings(cls_ast, self.module, cls=self)
+
+ for n in (cls_ast.body if '__init__' in public else []):
+ if isinstance(n, ast.FunctionDef) and n.name == '__init__':
+ self.doc_init = _var_docstrings(n, self.module,
+ cls=self, init=True)
+ break
+ except:
+ pass
+
+ # Convert the public Python objects to documentation objects.
+ for name, obj in public.items():
+ # Skip any identifiers that already have doco.
+ if name in self.doc and not self.doc[name].is_empty():
+ continue
+ if name in self.doc_init:
+ # Let instance members override class members.
+ continue
+
+ if inspect.ismethod(obj):
+ self.doc[name] = Function(name, self.module, obj.__func__,
+ cls=self, method=True)
+ elif inspect.isfunction(obj):
+ self.doc[name] = Function(name, self.module, obj,
+ cls=self, method=False)
+ elif isinstance(obj, property):
+ docstring = getattr(obj, '__doc__', '')
+ self.doc_init[name] = Variable(name, self.module, docstring,
+ cls=self)
+ elif not inspect.isbuiltin(obj) \
+ and not inspect.isroutine(obj):
+ if name in getattr(self.cls, '__slots__', []):
+ self.doc_init[name] = Variable(name, self.module,
+ '', cls=self)
+ else:
+ self.doc[name] = Variable(name, self.module, '', cls=self)
+
+ @property
+ def source(self):
+ return _source(self.cls)
+
+ @property
+ def refname(self):
+ return '%s.%s' % (self.module.refname, self.cls.__name__)
+
+ def class_variables(self):
+ """
+ Returns all documented class variables in the class, sorted
+ alphabetically as a list of `pdoc.Variable`.
+ """
+ p = lambda o: isinstance(o, Variable) and self.module._docfilter(o)
+ return sorted(filter(p, self.doc.values()))
+
+ def instance_variables(self):
+ """
+ Returns all instance variables in the class, sorted
+ alphabetically as a list of `pdoc.Variable`. Instance variables
+ are attributes of `self` defined in a class's `__init__`
+ method.
+ """
+ p = lambda o: isinstance(o, Variable) and self.module._docfilter(o)
+ return sorted(filter(p, self.doc_init.values()))
+
+ def methods(self):
+ """
+ Returns all documented methods as `pdoc.Function` objects in
+ the class, sorted alphabetically with `__init__` always coming
+ first.
+
+ Unfortunately, this also includes class methods.
+ """
+ p = lambda o: (isinstance(o, Function)
+ and o.method
+ and self.module._docfilter(o))
+ return sorted(filter(p, self.doc.values()))
+
+ def functions(self):
+ """
+ Returns all documented static functions as `pdoc.Function`
+ objects in the class, sorted alphabetically.
+ """
+ p = lambda o: (isinstance(o, Function)
+ and not o.method
+ and self.module._docfilter(o))
+ return sorted(filter(p, self.doc.values()))
+
+ def _fill_inheritance(self):
+ """
+ Traverses this class's ancestor list and attempts to fill in
+ missing documentation from its ancestor's documentation.
+
+ The first pass connects variables, methods and functions with
+ their inherited couterparts. (The templates will decide how to
+ display docstrings.) The second pass attempts to add instance
+ variables to this class that were only explicitly declared in
+ a parent class. This second pass is necessary since instance
+ variables are only discoverable by traversing the abstract
+ syntax tree.
+ """
+ mro = filter(lambda c: c != self and isinstance(c, Class),
+ self.module.mro(self))
+
+ def search(d, fdoc):
+ for c in mro:
+ doc = fdoc(c)
+ if d.name in doc and isinstance(d, type(doc[d.name])):
+ return doc[d.name]
+ return None
+ for fdoc in (lambda c: c.doc_init, lambda c: c.doc):
+ for d in fdoc(self).values():
+ dinherit = search(d, fdoc)
+ if dinherit is not None:
+ d.inherits = dinherit
+
+ # Since instance variables aren't part of a class's members,
+ # we need to manually deduce inheritance. Oh lawdy.
+ for c in mro:
+ for name in filter(lambda n: n not in self.doc_init, c.doc_init):
+ d = c.doc_init[name]
+ self.doc_init[name] = Variable(d.name, d.module, '', cls=self)
+ self.doc_init[name].inherits = d
+
+ def __public_objs(self):
+ """
+ Returns a dictionary mapping a public identifier name to a
+ Python object. This counts the `__init__` method as being
+ public.
+ """
+ _pdoc = getattr(self.module.module, '__pdoc__', {})
+
+ def forced_out(name):
+ return _pdoc.get('%s.%s' % (self.name, name), False) is None
+
+ def exported(name):
+ exported = name == '__init__' or _is_exported(name)
+ return not forced_out(name) and exported
+
+ idents = dict(inspect.getmembers(self.cls))
+ return dict([(n, o) for n, o in idents.items() if exported(n)])
+
+
+class Function (Doc):
+ """
+ Representation of documentation for a Python function or method.
+ """
+
+ def __init__(self, name, module, func_obj, cls=None, method=False):
+ """
+ Same as `pdoc.Doc.__init__`, except `func_obj` must be a
+ Python function object. The docstring is gathered automatically.
+
+ `cls` should be set when this is a method or a static function
+ beloing to a class. `cls` should be a `pdoc.Class` object.
+
+ `method` should be `True` when the function is a method. In
+ all other cases, it should be `False`.
+ """
+ super(Function, self).__init__(name, module, inspect.getdoc(func_obj))
+
+ self.func = func_obj
+ """The Python function object."""
+
+ self.cls = cls
+ """
+ The `pdoc.Class` documentation object if this is a method. If
+ not, this is None.
+ """
+
+ self.method = method
+ """
+ Whether this function is a method or not.
+
+ In particular, static class methods have this set to False.
+ """
+
+ @property
+ def source(self):
+ return _source(self.func)
+
+ @property
+ def refname(self):
+ if self.cls is None:
+ return '%s.%s' % (self.module.refname, self.name)
+ else:
+ return '%s.%s' % (self.cls.refname, self.name)
+
+ def spec(self):
+ """
+ Returns a nicely formatted spec of the function's parameter
+ list as a string. This includes argument lists, keyword
+ arguments and default values.
+ """
+ return ', '.join(self.params())
+
+ def params(self):
+ """
+ Returns a list where each element is a nicely formatted
+ parameter of this function. This includes argument lists,
+ keyword arguments and default values.
+ """
+ def fmt_param(el):
+ if isinstance(el, str) or isinstance(el, unicode):
+ return el
+ else:
+ return '(%s)' % (', '.join(map(fmt_param, el)))
+ try:
+ getspec = getattr(inspect, 'getfullargspec', inspect.getargspec)
+ s = getspec(self.func)
+ except TypeError:
+ # I guess this is for C builtin functions?
+ return ['...']
+
+ params = []
+ for i, param in enumerate(s.args):
+ if s.defaults is not None and len(s.args) - i <= len(s.defaults):
+ defind = len(s.defaults) - (len(s.args) - i)
+ params.append('%s=%s' % (param, repr(s.defaults[defind])))
+ else:
+ params.append(fmt_param(param))
+ if s.varargs is not None:
+ params.append('*%s' % s.varargs)
+
+ # TODO: This needs to be adjusted in Python 3. There's more stuff
+ # returned from getfullargspec than what we're looking at here.
+ keywords = getattr(s, 'varkw', getattr(s, 'keywords', None))
+ if keywords is not None:
+ params.append('**%s' % keywords)
+ return params
+
+ def __lt__(self, other):
+ # Push __init__ to the top.
+ if '__init__' in (self.name, other.name):
+ return self.name != other.name and self.name == '__init__'
+ else:
+ return self.name < other.name
+
+
+class Variable (Doc):
+ """
+ Representation of a variable's documentation. This includes
+ module, class and instance variables.
+ """
+
+ def __init__(self, name, module, docstring, cls=None):
+ """
+ Same as `pdoc.Doc.__init__`, except `cls` should be provided
+ as a `pdoc.Class` object when this is a class or instance
+ variable.
+ """
+ super(Variable, self).__init__(name, module, docstring)
+
+ self.cls = cls
+ """
+ The `podc.Class` object if this is a class or instance
+ variable. If not, this is None.
+ """
+
+ @property
+ def source(self):
+ return []
+
+ @property
+ def refname(self):
+ if self.cls is None:
+ return '%s.%s' % (self.module.refname, self.name)
+ else:
+ return '%s.%s' % (self.cls.refname, self.name)
+
+
+class External (Doc):
+ """
+ A representation of an external identifier. The textual
+ representation is the same as an internal identifier, but without
+ any context. (Usually this makes linking more difficult.)
+
+ External identifiers are also used to represent something that is
+ not exported but appears somewhere in the public interface (like
+ the ancestor list of a class).
+ """
+
+ __pdoc__['External.docstring'] = \
+ """
+ An empty string. External identifiers do not have
+ docstrings.
+ """
+ __pdoc__['External.module'] = \
+ """
+ Always `None`. External identifiers have no associated
+ `pdoc.Module`.
+ """
+ __pdoc__['External.name'] = \
+ """
+ Always equivalent to `pdoc.External.refname` since external
+ identifiers are always expressed in their fully qualified
+ form.
+ """
+
+ def __init__(self, name):
+ """
+ Initializes an external identifier with `name`, where `name`
+ should be a fully qualified name.
+ """
+ super(External, self).__init__(name, None, '')
+
+ @property
+ def source(self):
+ return []
+
+ @property
+ def refname(self):
+ return self.name
diff --git a/ext_libs/pdoc/templates/LICENSE b/ext_libs/pdoc/templates/LICENSE
new file mode 100644
index 000000000..294e91d80
--- /dev/null
+++ b/ext_libs/pdoc/templates/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) HTML5 Boilerplate
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/ext_libs/pdoc/templates/README.md b/ext_libs/pdoc/templates/README.md
new file mode 100644
index 000000000..a396ff5d2
--- /dev/null
+++ b/ext_libs/pdoc/templates/README.md
@@ -0,0 +1,3 @@
+The license included in this directory is for
+[HTML5 Boiler Plate](http://html5boilerplate.com). Some of the HTML and CSS
+used here is derived from that project.
diff --git a/ext_libs/pdoc/templates/css.mako b/ext_libs/pdoc/templates/css.mako
new file mode 100644
index 000000000..1c3ac6c87
--- /dev/null
+++ b/ext_libs/pdoc/templates/css.mako
@@ -0,0 +1,928 @@
+<%def name="pdoc()">
+ html, body {
+ margin: 0;
+ padding: 0;
+ min-height: 100%;
+ }
+ body {
+ background: #fff;
+ font-family: "Source Sans Pro", "Helvetica Neueue", Helvetica, sans;
+ font-weight: 300;
+ font-size: 16px;
+ line-height: 1.6em;
+ }
+ #content {
+ width: 70%;
+ max-width: 850px;
+ float: left;
+ padding: 30px 60px;
+ border-left: 1px solid #ddd;
+ }
+ #sidebar {
+ width: 25%;
+ float: left;
+ padding: 30px;
+ overflow: hidden;
+ }
+ #nav {
+ font-size: 130%;
+ margin: 0 0 15px 0;
+ }
+
+ #top {
+ display: block;
+ position: fixed;
+ bottom: 5px;
+ left: 5px;
+ font-size: .85em;
+ text-transform: uppercase;
+ }
+
+ #footer {
+ font-size: .75em;
+ padding: 5px 30px;
+ border-top: 1px solid #ddd;
+ text-align: right;
+ }
+ #footer p {
+ margin: 0 0 0 30px;
+ display: inline-block;
+ }
+
+ h1, h2, h3, h4, h5 {
+ font-weight: 300;
+ }
+ h1 {
+ font-size: 2.5em;
+ line-height: 1.1em;
+ margin: 0 0 .50em 0;
+ }
+
+ h2 {
+ font-size: 1.75em;
+ margin: 1em 0 .50em 0;
+ }
+
+ h3 {
+ margin: 25px 0 10px 0;
+ }
+
+ h4 {
+ margin: 0;
+ font-size: 105%;
+ }
+
+ a {
+ color: #058;
+ text-decoration: none;
+ transition: color .3s ease-in-out;
+ }
+
+ a:hover {
+ color: #e08524;
+ transition: color .3s ease-in-out;
+ }
+
+ pre, code, .mono, .name {
+ font-family: "Ubuntu Mono", "Cousine", "DejaVu Sans Mono", monospace;
+ }
+
+ .title .name {
+ font-weight: bold;
+ }
+ .section-title {
+ margin-top: 2em;
+ }
+ .ident {
+ color: #900;
+ }
+
+ code {
+ background: #f9f9f9;
+ }
+
+ pre {
+ background: #fefefe;
+ border: 1px solid #ddd;
+ box-shadow: 2px 2px 0 #f3f3f3;
+ margin: 0 30px;
+ padding: 15px 30px;
+ }
+
+ .codehilite {
+ margin: 0 30px 10px 30px;
+ }
+
+ .codehilite pre {
+ margin: 0;
+ }
+ .codehilite .err { background: #ff3300; color: #fff !important; }
+
+ table#module-list {
+ font-size: 110%;
+ }
+
+ table#module-list tr td:first-child {
+ padding-right: 10px;
+ white-space: nowrap;
+ }
+
+ table#module-list td {
+ vertical-align: top;
+ padding-bottom: 8px;
+ }
+
+ table#module-list td p {
+ margin: 0 0 7px 0;
+ }
+
+ .def {
+ display: table;
+ }
+
+ .def p {
+ display: table-cell;
+ vertical-align: top;
+ text-align: left;
+ }
+
+ .def p:first-child {
+ white-space: nowrap;
+ }
+
+ .def p:last-child {
+ width: 100%;
+ }
+
+
+ #index {
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+ }
+ ul#index .class_name {
+ /* font-size: 110%; */
+ font-weight: bold;
+ }
+ #index ul {
+ margin: 0;
+ }
+
+ .item {
+ margin: 0 0 15px 0;
+ }
+
+ .item .class {
+ margin: 0 0 25px 30px;
+ }
+
+ .item .class ul.class_list {
+ margin: 0 0 20px 0;
+ }
+
+ .item .name {
+ background: #fafafa;
+ margin: 0;
+ font-weight: bold;
+ padding: 5px 10px;
+ border-radius: 3px;
+ display: inline-block;
+ min-width: 40%;
+ }
+ .item .name:hover {
+ background: #f6f6f6;
+ }
+
+ .item .empty_desc {
+ margin: 0 0 5px 0;
+ padding: 0;
+ }
+
+ .item .inheritance {
+ margin: 3px 0 0 30px;
+ }
+
+ .item .inherited {
+ color: #666;
+ }
+
+ .item .desc {
+ padding: 0 8px;
+ margin: 0;
+ }
+
+ .item .desc p {
+ margin: 0 0 10px 0;
+ }
+
+ .source_cont {
+ margin: 0;
+ padding: 0;
+ }
+
+ .source_link a {
+ background: #ffc300;
+ font-weight: 400;
+ font-size: .75em;
+ text-transform: uppercase;
+ color: #fff;
+ text-shadow: 1px 1px 0 #f4b700;
+
+ padding: 3px 8px;
+ border-radius: 2px;
+ transition: background .3s ease-in-out;
+ }
+ .source_link a:hover {
+ background: #FF7200;
+ text-shadow: none;
+ transition: background .3s ease-in-out;
+ }
+
+ .source {
+ display: none;
+ max-height: 600px;
+ overflow-y: scroll;
+ margin-bottom: 15px;
+ }
+
+ .source .codehilite {
+ margin: 0;
+ }
+
+ .desc h1, .desc h2, .desc h3 {
+ font-size: 100% !important;
+ }
+ .clear {
+ clear: both;
+ }
+
+ @media all and (max-width: 950px) {
+ #sidebar {
+ width: 35%;
+ }
+ #content {
+ width: 65%;
+ }
+ }
+ @media all and (max-width: 650px) {
+ #top {
+ display: none;
+ }
+ #sidebar {
+ float: none;
+ width: auto;
+ }
+ #content {
+ float: none;
+ width: auto;
+ padding: 30px;
+ }
+
+ #index ul {
+ padding: 0;
+ margin-bottom: 15px;
+ }
+ #index ul li {
+ display: inline-block;
+ margin-right: 30px;
+ }
+ #footer {
+ text-align: left;
+ }
+ #footer p {
+ display: block;
+ margin: inherit;
+ }
+ }
+
+ /*****************************/
+%def>
+<%def name="pre()">
+* {
+ box-sizing: border-box;
+}
+/*! normalize.css v1.1.1 | MIT License | git.io/normalize */
+
+/* ==========================================================================
+ HTML5 display definitions
+ ========================================================================== */
+
+/**
+ * Correct `block` display not defined in IE 6/7/8/9 and Firefox 3.
+ */
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+nav,
+section,
+summary {
+ display: block;
+}
+
+/**
+ * Correct `inline-block` display not defined in IE 6/7/8/9 and Firefox 3.
+ */
+
+audio,
+canvas,
+video {
+ display: inline-block;
+ *display: inline;
+ *zoom: 1;
+}
+
+/**
+ * Prevent modern browsers from displaying `audio` without controls.
+ * Remove excess height in iOS 5 devices.
+ */
+
+audio:not([controls]) {
+ display: none;
+ height: 0;
+}
+
+/**
+ * Address styling not present in IE 7/8/9, Firefox 3, and Safari 4.
+ * Known issue: no IE 6 support.
+ */
+
+[hidden] {
+ display: none;
+}
+
+/* ==========================================================================
+ Base
+ ========================================================================== */
+
+/**
+ * 1. Prevent system color scheme's background color being used in Firefox, IE,
+ * and Opera.
+ * 2. Prevent system color scheme's text color being used in Firefox, IE, and
+ * Opera.
+ * 3. Correct text resizing oddly in IE 6/7 when body `font-size` is set using
+ * `em` units.
+ * 4. Prevent iOS text size adjust after orientation change, without disabling
+ * user zoom.
+ */
+
+html {
+ background: #fff; /* 1 */
+ color: #000; /* 2 */
+ font-size: 100%; /* 3 */
+ -webkit-text-size-adjust: 100%; /* 4 */
+ -ms-text-size-adjust: 100%; /* 4 */
+}
+
+/**
+ * Address `font-family` inconsistency between `textarea` and other form
+ * elements.
+ */
+
+html,
+button,
+input,
+select,
+textarea {
+ font-family: sans-serif;
+}
+
+/**
+ * Address margins handled incorrectly in IE 6/7.
+ */
+
+body {
+ margin: 0;
+}
+
+/* ==========================================================================
+ Links
+ ========================================================================== */
+
+/**
+ * Address `outline` inconsistency between Chrome and other browsers.
+ */
+
+a:focus {
+ outline: thin dotted;
+}
+
+/**
+ * Improve readability when focused and also mouse hovered in all browsers.
+ */
+
+a:active,
+a:hover {
+ outline: 0;
+}
+
+/* ==========================================================================
+ Typography
+ ========================================================================== */
+
+/**
+ * Address font sizes and margins set differently in IE 6/7.
+ * Address font sizes within `section` and `article` in Firefox 4+, Safari 5,
+ * and Chrome.
+ */
+
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+
+h2 {
+ font-size: 1.5em;
+ margin: 0.83em 0;
+}
+
+h3 {
+ font-size: 1.17em;
+ margin: 1em 0;
+}
+
+h4 {
+ font-size: 1em;
+ margin: 1.33em 0;
+}
+
+h5 {
+ font-size: 0.83em;
+ margin: 1.67em 0;
+}
+
+h6 {
+ font-size: 0.67em;
+ margin: 2.33em 0;
+}
+
+/**
+ * Address styling not present in IE 7/8/9, Safari 5, and Chrome.
+ */
+
+abbr[title] {
+ border-bottom: 1px dotted;
+}
+
+/**
+ * Address style set to `bolder` in Firefox 3+, Safari 4/5, and Chrome.
+ */
+
+b,
+strong {
+ font-weight: bold;
+}
+
+blockquote {
+ margin: 1em 40px;
+}
+
+/**
+ * Address styling not present in Safari 5 and Chrome.
+ */
+
+dfn {
+ font-style: italic;
+}
+
+/**
+ * Address differences between Firefox and other browsers.
+ * Known issue: no IE 6/7 normalization.
+ */
+
+hr {
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+ height: 0;
+}
+
+/**
+ * Address styling not present in IE 6/7/8/9.
+ */
+
+mark {
+ background: #ff0;
+ color: #000;
+}
+
+/**
+ * Address margins set differently in IE 6/7.
+ */
+
+p,
+pre {
+ margin: 1em 0;
+}
+
+/**
+ * Correct font family set oddly in IE 6, Safari 4/5, and Chrome.
+ */
+
+code,
+kbd,
+pre,
+samp {
+ font-family: monospace, serif;
+ _font-family: 'courier new', monospace;
+ font-size: 1em;
+}
+
+/**
+ * Improve readability of pre-formatted text in all browsers.
+ */
+
+pre {
+ white-space: pre;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+
+/**
+ * Address CSS quotes not supported in IE 6/7.
+ */
+
+q {
+ quotes: none;
+}
+
+/**
+ * Address `quotes` property not supported in Safari 4.
+ */
+
+q:before,
+q:after {
+ content: '';
+ content: none;
+}
+
+/**
+ * Address inconsistent and variable font size in all browsers.
+ */
+
+small {
+ font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` affecting `line-height` in all browsers.
+ */
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sup {
+ top: -0.5em;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+/* ==========================================================================
+ Lists
+ ========================================================================== */
+
+/**
+ * Address margins set differently in IE 6/7.
+ */
+
+dl,
+menu,
+ol,
+ul {
+ margin: 1em 0;
+}
+
+dd {
+ margin: 0 0 0 40px;
+}
+
+/**
+ * Address paddings set differently in IE 6/7.
+ */
+
+menu,
+ol,
+ul {
+ padding: 0 0 0 40px;
+}
+
+/**
+ * Correct list images handled incorrectly in IE 7.
+ */
+
+nav ul,
+nav ol {
+ list-style: none;
+ list-style-image: none;
+}
+
+/* ==========================================================================
+ Embedded content
+ ========================================================================== */
+
+/**
+ * 1. Remove border when inside `a` element in IE 6/7/8/9 and Firefox 3.
+ * 2. Improve image quality when scaled in IE 7.
+ */
+
+img {
+ border: 0; /* 1 */
+ -ms-interpolation-mode: bicubic; /* 2 */
+}
+
+/**
+ * Correct overflow displayed oddly in IE 9.
+ */
+
+svg:not(:root) {
+ overflow: hidden;
+}
+
+/* ==========================================================================
+ Figures
+ ========================================================================== */
+
+/**
+ * Address margin not present in IE 6/7/8/9, Safari 5, and Opera 11.
+ */
+
+figure {
+ margin: 0;
+}
+
+/* ==========================================================================
+ Forms
+ ========================================================================== */
+
+/**
+ * Correct margin displayed oddly in IE 6/7.
+ */
+
+form {
+ margin: 0;
+}
+
+/**
+ * Define consistent border, margin, and padding.
+ */
+
+fieldset {
+ border: 1px solid #c0c0c0;
+ margin: 0 2px;
+ padding: 0.35em 0.625em 0.75em;
+}
+
+/**
+ * 1. Correct color not being inherited in IE 6/7/8/9.
+ * 2. Correct text not wrapping in Firefox 3.
+ * 3. Correct alignment displayed oddly in IE 6/7.
+ */
+
+legend {
+ border: 0; /* 1 */
+ padding: 0;
+ white-space: normal; /* 2 */
+ *margin-left: -7px; /* 3 */
+}
+
+/**
+ * 1. Correct font size not being inherited in all browsers.
+ * 2. Address margins set differently in IE 6/7, Firefox 3+, Safari 5,
+ * and Chrome.
+ * 3. Improve appearance and consistency in all browsers.
+ */
+
+button,
+input,
+select,
+textarea {
+ font-size: 100%; /* 1 */
+ margin: 0; /* 2 */
+ vertical-align: baseline; /* 3 */
+ *vertical-align: middle; /* 3 */
+}
+
+/**
+ * Address Firefox 3+ setting `line-height` on `input` using `!important` in
+ * the UA stylesheet.
+ */
+
+button,
+input {
+ line-height: normal;
+}
+
+/**
+ * Address inconsistent `text-transform` inheritance for `button` and `select`.
+ * All other form control elements do not inherit `text-transform` values.
+ * Correct `button` style inheritance in Chrome, Safari 5+, and IE 6+.
+ * Correct `select` style inheritance in Firefox 4+ and Opera.
+ */
+
+button,
+select {
+ text-transform: none;
+}
+
+/**
+ * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
+ * and `video` controls.
+ * 2. Correct inability to style clickable `input` types in iOS.
+ * 3. Improve usability and consistency of cursor style between image-type
+ * `input` and others.
+ * 4. Remove inner spacing in IE 7 without affecting normal text inputs.
+ * Known issue: inner spacing remains in IE 6.
+ */
+
+button,
+html input[type="button"], /* 1 */
+input[type="reset"],
+input[type="submit"] {
+ -webkit-appearance: button; /* 2 */
+ cursor: pointer; /* 3 */
+ *overflow: visible; /* 4 */
+}
+
+/**
+ * Re-set default cursor for disabled elements.
+ */
+
+button[disabled],
+html input[disabled] {
+ cursor: default;
+}
+
+/**
+ * 1. Address box sizing set to content-box in IE 8/9.
+ * 2. Remove excess padding in IE 8/9.
+ * 3. Remove excess padding in IE 7.
+ * Known issue: excess padding remains in IE 6.
+ */
+
+input[type="checkbox"],
+input[type="radio"] {
+ box-sizing: border-box; /* 1 */
+ padding: 0; /* 2 */
+ *height: 13px; /* 3 */
+ *width: 13px; /* 3 */
+}
+
+/**
+ * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
+ * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
+ * (include `-moz` to future-proof).
+ */
+
+input[type="search"] {
+ -webkit-appearance: textfield; /* 1 */
+ -moz-box-sizing: content-box;
+ -webkit-box-sizing: content-box; /* 2 */
+ box-sizing: content-box;
+}
+
+/**
+ * Remove inner padding and search cancel button in Safari 5 and Chrome
+ * on OS X.
+ */
+
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+/**
+ * Remove inner padding and border in Firefox 3+.
+ */
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+ border: 0;
+ padding: 0;
+}
+
+/**
+ * 1. Remove default vertical scrollbar in IE 6/7/8/9.
+ * 2. Improve readability and alignment in all browsers.
+ */
+
+textarea {
+ overflow: auto; /* 1 */
+ vertical-align: top; /* 2 */
+}
+
+/* ==========================================================================
+ Tables
+ ========================================================================== */
+
+/**
+ * Remove most spacing between table cells.
+ */
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+%def>
+
+<%def name="post()">
+/* ==========================================================================
+ EXAMPLE Media Queries for Responsive Design.
+ These examples override the primary ('mobile first') styles.
+ Modify as content requires.
+ ========================================================================== */
+
+@media only screen and (min-width: 35em) {
+ /* Style adjustments for viewports that meet the condition */
+}
+
+@media print,
+ (-o-min-device-pixel-ratio: 5/4),
+ (-webkit-min-device-pixel-ratio: 1.25),
+ (min-resolution: 120dpi) {
+ /* Style adjustments for high resolution devices */
+}
+
+/* ==========================================================================
+ Print styles.
+ Inlined to avoid required HTTP connection: h5bp.com/r
+ ========================================================================== */
+
+@media print {
+ * {
+ background: transparent !important;
+ color: #000 !important; /* Black prints faster: h5bp.com/s */
+ box-shadow: none !important;
+ text-shadow: none !important;
+ }
+
+ a,
+ a:visited {
+ text-decoration: underline;
+ }
+
+ a[href]:after {
+ content: " (" attr(href) ")";
+ }
+
+ abbr[title]:after {
+ content: " (" attr(title) ")";
+ }
+
+ /*
+ * Don't show links for images, or javascript/internal links
+ */
+
+ .ir a:after,
+ a[href^="javascript:"]:after,
+ a[href^="#"]:after {
+ content: "";
+ }
+
+ pre,
+ blockquote {
+ border: 1px solid #999;
+ page-break-inside: avoid;
+ }
+
+ thead {
+ display: table-header-group; /* h5bp.com/t */
+ }
+
+ tr,
+ img {
+ page-break-inside: avoid;
+ }
+
+ img {
+ max-width: 100% !important;
+ }
+
+ @page {
+ margin: 0.5cm;
+ }
+
+ p,
+ h2,
+ h3 {
+ orphans: 3;
+ widows: 3;
+ }
+
+ h2,
+ h3 {
+ page-break-after: avoid;
+ }
+}
+%def>
diff --git a/ext_libs/pdoc/templates/html.mako b/ext_libs/pdoc/templates/html.mako
new file mode 100644
index 000000000..46a1726d2
--- /dev/null
+++ b/ext_libs/pdoc/templates/html.mako
@@ -0,0 +1,484 @@
+<%
+ import re
+ import sys
+
+ import markdown
+ try:
+ import pygments
+ import pygments.formatters
+ import pygments.lexers
+ use_pygments = True
+ except ImportError:
+ use_pygments = False
+
+ import pdoc
+
+ # From language reference, but adds '.' to allow fully qualified names.
+ pyident = re.compile('^[a-zA-Z_][a-zA-Z0-9_.]+$')
+ indent = re.compile('^\s*')
+
+ # Whether we're showing the module list or a single module.
+ module_list = 'modules' in context.keys()
+
+ def decode(s):
+ if sys.version_info[0] < 3 and isinstance(s, str):
+ return s.decode('utf-8', 'ignore')
+ return s
+
+ def ident(s):
+ return '%s' % s
+
+ def sourceid(dobj):
+ return 'source-%s' % dobj.refname
+
+ def clean_source_lines(lines):
+ """
+ Cleans the source code so that pygments can render it well.
+
+ Returns one string with all of the source code.
+ """
+ base_indent = len(indent.match(lines[0]).group(0))
+ base_indent = 0
+ for line in lines:
+ if len(line.strip()) > 0:
+ base_indent = len(indent.match(lines[0]).group(0))
+ break
+ lines = [line[base_indent:] for line in lines]
+ if not use_pygments: # :-(
+ return '
%s
' % (''.join(lines))
+
+ pylex = pygments.lexers.PythonLexer()
+ htmlform = pygments.formatters.HtmlFormatter(cssclass='codehilite')
+ return pygments.highlight(''.join(lines), pylex, htmlform)
+
+ def linkify(match):
+ matched = match.group(0)
+ ident = matched[1:-1]
+ name, url = lookup(ident)
+ if name is None:
+ return matched
+ return '[`%s`](%s)' % (name, url)
+
+ def mark(s, linky=True):
+ if linky:
+ s, _ = re.subn('\b\n\b', ' ', s)
+ if not module_list:
+ s, _ = re.subn('`[^`]+`', linkify, s)
+
+ extensions = []
+ if use_pygments:
+ extensions = ['markdown.extensions.codehilite(linenums=False)']
+ s = markdown.markdown(s.strip(), extensions=extensions)
+ return s
+
+ def glimpse(s, length=100):
+ if len(s) < length:
+ return s
+ return s[0:length] + '...'
+
+ def module_url(m):
+ """
+ Returns a URL for `m`, which must be an instance of `Module`.
+ Also, `m` must be a submodule of the module being documented.
+
+ Namely, '.' import separators are replaced with '/' URL
+ separators. Also, packages are translated as directories
+ containing `index.html` corresponding to the `__init__` module,
+ while modules are translated as regular HTML files with an
+ `.m.html` suffix. (Given default values of
+ `pdoc.html_module_suffix` and `pdoc.html_package_name`.)
+ """
+ if module.name == m.name:
+ return ''
+
+ if len(link_prefix) > 0:
+ base = m.name
+ else:
+ base = m.name[len(module.name)+1:]
+ url = base.replace('.', '/')
+ if m.is_package():
+ url += '/%s' % pdoc.html_package_name
+ else:
+ url += pdoc.html_module_suffix
+ return link_prefix + url
+
+ def external_url(refname):
+ """
+ Attempts to guess an absolute URL for the external identifier
+ given.
+
+ Note that this just returns the refname with an ".ext" suffix.
+ It will be up to whatever is interpreting the URLs to map it
+ to an appropriate documentation page.
+ """
+ return '/%s.ext' % refname
+
+ def is_external_linkable(name):
+ return external_links and pyident.match(name) and '.' in name
+
+ def lookup(refname):
+ """
+ Given a fully qualified identifier name, return its refname
+ with respect to the current module and a value for a `href`
+ attribute. If `refname` is not in the public interface of
+ this module or its submodules, then `None` is returned for
+ both return values. (Unless this module has enabled external
+ linking.)
+
+ In particular, this takes into account sub-modules and external
+ identifiers. If `refname` is in the public API of the current
+ module, then a local anchor link is given. If `refname` is in the
+ public API of a sub-module, then a link to a different page with
+ the appropriate anchor is given. Otherwise, `refname` is
+ considered external and no link is used.
+ """
+ d = module.find_ident(refname)
+ if isinstance(d, pdoc.External):
+ if is_external_linkable(refname):
+ return d.refname, external_url(d.refname)
+ else:
+ return None, None
+ if isinstance(d, pdoc.Module):
+ return d.refname, module_url(d)
+ if module.is_public(d.refname):
+ return d.name, '#%s' % d.refname
+ return d.refname, '%s#%s' % (module_url(d.module), d.refname)
+
+ def link(refname):
+ """
+ A convenience wrapper around `href` to produce the full
+ `a` tag if `refname` is found. Otherwise, plain text of
+ `refname` is returned.
+ """
+ name, url = lookup(refname)
+ if name is None:
+ return refname
+ return '%s' % (url, name)
+%>
+<%def name="show_source(d)">
+ % if show_source_code and d.source is not None and len(d.source) > 0:
+
+
+ Inheritance:
+ % if hasattr(d.inherits, 'cls'):
+ ${link(d.inherits.cls.refname)}
.${link(d.inherits.refname)}
+ % else:
+ ${link(d.inherits.refname)}
+ % endif
+
No modules found.
+% else: +${name} | +
+ % if len(desc.strip()) > 0:
+ ${desc | mark}
+ % endif
+ |
+
def ${ident(f.name)}(
${f.spec() | h})
+var ${ident(v.name)}
+ ${show_desc(v)} +class ${ident(c.name)}
+ ${show_desc(c)} + +var ${ident(v.name)}
+ ${show_inheritance(v)} + ${show_desc(v)} +var ${ident(v.name)}
+ ${show_inheritance(v)} + ${show_desc(v)} +${link(m.refname)}
+ ${show_desc(m, limit=300)} +