[Python-modules-commits] [sphinx-celery] 01/04: Adds sphinx_celery.apicheck extension, replacing celerys extra/release/doc4allmods
Christopher Stuart Hoskin
mans0954 at moszumanska.debian.org
Fri Aug 18 07:00:21 UTC 2017
This is an automated email from the git hooks/post-receive script.
mans0954 pushed a commit to tag v1.1.0
in repository sphinx-celery.
commit dc953bb8cd8cbee337cd6ddd50705aef2f245efe
Author: Ask Solem <ask at celeryproject.org>
Date: Fri Apr 8 13:30:54 2016 -0700
Adds sphinx_celery.apicheck extension, replacing celerys extra/release/doc4allmods
---
sphinx_celery/apicheck.py | 225 ++++++++++++++++++++++++++++++++++++++++++++++
sphinx_celery/conf.py | 1 +
2 files changed, 226 insertions(+)
diff --git a/sphinx_celery/apicheck.py b/sphinx_celery/apicheck.py
new file mode 100644
index 0000000..5ab2076
--- /dev/null
+++ b/sphinx_celery/apicheck.py
@@ -0,0 +1,225 @@
+"""
+
+Sphinx Autodoc coverage checker.
+================================
+
+This builder extension makes sure all modules in the documented
+package is represented in the autodoc API reference.
+
+Usage
+-----
+
+.. code-block:: console
+
+ $ sphinx-build -b apicheck -d _build/doctrees . _build/apicheck
+
+Configuration
+-------------
+
+apicheck_ignore_modules
+~~~~~~~~~~~~~~~~~~~~~~~
+
+List of modules to ignore, either as module names or regexes.
+
+Example:
+
+.. code-block:: python
+
+ apicheck_ignore_modules = [
+ 'django.utils.functional',
+ r'django.db.*',
+ ]
+
+Test packages are ignored by default, even if this setting is defined.
+
+apicheck_package
+~~~~~~~~~~~~~~~~
+
+The package to verify, can be the fully-qualified name of a module
+or an actual module.
+
+Example:
+
+.. code-block:: python
+
+ apicheck_package = 'django'
+
+Default is the value of the ``project`` configuration key in all lowercase.
+
+
+apicheck_domains
+~~~~~~~~~~~~~~~~
+
+List of domains to check.
+
+Default is ``['py']`` and Python is the only domain currently supported.
+
+"""
+from __future__ import absolute_import, unicode_literals
+
+import importlib
+import os
+import pickle
+import re
+
+from collections import defaultdict
+from six import string_types
+
+from sphinx.builders import Builder
+from sphinx.util.console import bold, darkgreen, green, red
+
+from .utils import bytes_if_py2
+
+DEFAULT_IGNORE = [r'.*?\.tests.*']
+
+TITLEHEADER = '='
+SUBHEADER = '-'
+
+ERR_MISSING = 'Undocumented Autodoc Modules'
+ERR_INVALID_REGEX = 'Invalid regex {0!r} in apicheck_ignore_modules: {1!r}'
+
+OK_STATUS = 'OK: All modules documented :o)'
+
+NOK_STATUS = """
+{title}
+
+{undocumented}\
+"""
+
+DOMAIN_FORMAT = """\
+{domain}
+
+{modules}
+"""
+
+MODULE_FORMAT = '- {module}'
+
+
+def title(s, spacing=2, sep=TITLEHEADER):
+ return '\n'.join([
+ sep * (len(s) + spacing),
+ '{0}{1}{0}'.format(' ' * (spacing // 2), red(s)),
+ sep * (len(s) + spacing),
+ ])
+
+
+def header(s, sep=SUBHEADER):
+ return '\n'.join([bold(s), sep * len(s)])
+
+
+def find_python_modules(package):
+ if isinstance(package, string_types):
+ package = importlib.import_module(package)
+ name, path = package.__name__, package.__file__
+ current_dist_depth = len(name.split('.')) - 1
+ current_dist = os.path.join(os.path.dirname(path),
+ *([os.pardir] * current_dist_depth))
+ abs = os.path.abspath(current_dist)
+ dist_name = os.path.basename(abs)
+
+ for dirpath, dirnames, filenames in os.walk(abs):
+ package = (dist_name + dirpath[len(abs):]).replace('/', '.')
+ if '__init__.py' in filenames:
+ yield package
+ for filename in filenames:
+ if filename.endswith('.py') and filename != '__init__.py':
+ yield '.'.join([package, filename])[:-3]
+
+
+class APICheckBuilder(Builder):
+
+ name = 'apicheck'
+
+ find_modules = {
+ 'py': find_python_modules,
+ }
+
+ def init(self):
+ self.ignore_patterns = self.compile_regexes(
+ self.config.apicheck_ignore_modules + DEFAULT_IGNORE,
+ )
+ self.check_domains = self.config.apicheck_domains
+ self.check_package = (
+ self.config.apicheck_package or self.config.project.lower())
+
+ self.undocumented = defaultdict(list)
+
+ def compile_regex(self, regex):
+ if not regex.startswith('^'):
+ regex = '^{0}'.format(regex)
+ if not regex.endswith('$'):
+ regex = '{0}$'.format(regex)
+ try:
+ return re.compile(regex)
+ except Exception as exc:
+ self.warn(ERR_INVALID_REGEX.format(regex, exc))
+
+ def compile_regexes(self, regexes):
+ return [self.compile_regex(regex) for regex in regexes]
+
+ def get_outdated_docs(self):
+ return 'apicheck overview'
+
+ def is_ignored_module(self, module):
+ return any(regex.match(module) for regex in self.ignore_patterns)
+
+ def write(self, *ignored):
+ for domain in self.check_domains:
+ self.build_coverage(domain)
+ self.write_coverage(self.check_domains)
+
+ def build_coverage(self, domain):
+ self.undocumented[domain].extend(self.find_undocumented(
+ self.check_package, domain, self.env.domaindata[domain]['modules'],
+ ))
+
+ def find_undocumented(self, package, domain, documented):
+ return (
+ mod for mod in self.find_modules[domain](package)
+ if mod not in documented and not self.is_ignored_module(mod)
+ )
+
+ def write_coverage(self, domains):
+ status = any(self.undocumented.values())
+ if status:
+ self.app.statuscode = 2
+ print(self.format_undocumented_domains(domains))
+ else:
+ print(green(OK_STATUS))
+
+ def format_undocumented_domains(self, domains):
+ return NOK_STATUS.format(
+ title=title(ERR_MISSING),
+ undocumented='\n'.join(
+ self.format_undocumented_domain(domain) for domain in domains
+ ),
+ )
+
+ def format_undocumented_domain(self, domain):
+ return DOMAIN_FORMAT.format(domain=header(domain), modules='\n'.join(
+ self.format_undocumented_module(module)
+ for module in self.undocumented[domain]
+ ))
+
+ def format_undocumented_module(self, module):
+ return MODULE_FORMAT.format(module=darkgreen(module))
+
+ def as_dict(self):
+ return {
+ 'undocumented': dict(self.undocumented),
+ }
+
+ def finish(self):
+ picklepath = os.path.join(self.outdir, 'apicheck.pickle')
+ with open(picklepath, mode='wb') as fh:
+ pickle.dump(self.as_dict(), fh)
+
+
+def setup(app):
+ app.add_builder(APICheckBuilder)
+ app.add_config_value(
+ bytes_if_py2('apicheck_ignore_modules'), [".*?\.tests.*"], False)
+ app.add_config_value(
+ bytes_if_py2('apicheck_domains'), ['py'], False)
+ app.add_config_value(
+ bytes_if_py2('apicheck_package'), None, False)
diff --git a/sphinx_celery/conf.py b/sphinx_celery/conf.py
index 67582aa..ed353a9 100644
--- a/sphinx_celery/conf.py
+++ b/sphinx_celery/conf.py
@@ -25,6 +25,7 @@ EXTENSIONS = [
'sphinx_celery.github_issues',
'sphinx_celery.signal_crossref',
'sphinx_celery.setting_crossref',
+ 'sphinx_celery.apicheck',
]
INTERSPHINX_MAPPING = {
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/sphinx-celery.git
More information about the Python-modules-commits
mailing list