Skip to content

Commit

Permalink
Merge pull request #1375 from dhermes/check-left-out-modules
Browse files Browse the repository at this point in the history
Adding check that all public modules are documented.
dhermes committed Feb 12, 2016
2 parents b30d3f4 + 27da413 commit d56ea3d
Showing 9 changed files with 189 additions and 9 deletions.
7 changes: 7 additions & 0 deletions docs/bigquery-query.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Query
~~~~~

.. automodule:: gcloud.bigquery.query
:members:
:undoc-members:
:show-inheritance:
7 changes: 7 additions & 0 deletions docs/datastore-helpers.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Helpers
~~~~~~~

.. automodule:: gcloud.datastore.helpers
:members:
:undoc-members:
:show-inheritance:
8 changes: 8 additions & 0 deletions docs/gcloud-api.rst
Original file line number Diff line number Diff line change
@@ -33,3 +33,11 @@ Exceptions
:members:
:undoc-members:
:show-inheritance:

Environment Variables
~~~~~~~~~~~~~~~~~~~~~

.. automodule:: gcloud.environment_vars
:members:
:undoc-members:
:show-inheritance:
3 changes: 3 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@
datastore-queries
datastore-transactions
datastore-batches
datastore-helpers

.. toctree::
:maxdepth: 0
@@ -27,6 +28,7 @@
storage-blobs
storage-buckets
storage-acl
storage-batch

.. toctree::
:maxdepth: 0
@@ -49,6 +51,7 @@
bigquery-dataset
bigquery-job
bigquery-table
bigquery-query

.. toctree::
:maxdepth: 0
7 changes: 7 additions & 0 deletions docs/storage-batch.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Batches
~~~~~~~

.. automodule:: gcloud.storage.batch
:members:
:undoc-members:
:show-inheritance:
18 changes: 10 additions & 8 deletions scripts/run_pylint.py
Original file line number Diff line number Diff line change
@@ -21,6 +21,8 @@
violations (hence it has a reduced number of style checks).
"""

from __future__ import print_function

import ConfigParser
import copy
import os
@@ -152,12 +154,12 @@ def get_files_for_linting(allow_limited=True):
if diff_base is not None and allow_limited:
result = subprocess.check_output(['git', 'diff', '--name-only',
diff_base])
print 'Using files changed relative to %s:' % (diff_base,)
print '-' * 60
print result.rstrip('\n') # Don't print trailing newlines.
print '-' * 60
print('Using files changed relative to %s:' % (diff_base,))
print('-' * 60)
print(result.rstrip('\n')) # Don't print trailing newlines.
print('-' * 60)
else:
print 'Diff base not specified, listing all files in repository.'
print('Diff base not specified, listing all files in repository.')
result = subprocess.check_output(['git', 'ls-files'])

return result.rstrip('\n').split('\n'), diff_base
@@ -212,10 +214,10 @@ def lint_fileset(filenames, rcfile, description):
if status_code != 0:
error_message = ('Pylint failed on %s with '
'status %d.' % (description, status_code))
print >> sys.stderr, error_message
print(error_message, file=sys.stderr)
sys.exit(status_code)
else:
print 'Skipping %s, no files to lint.' % (description,)
print('Skipping %s, no files to lint.' % (description,))


def main():
@@ -230,7 +232,7 @@ def main():
raise

message = 'Restricted lint failed, expanding to full fileset.'
print >> sys.stderr, message
print(message, file=sys.stderr)
all_files, _ = get_files_for_linting(allow_limited=False)
library_files, non_library_files, _ = get_python_files(
all_files=all_files)
4 changes: 3 additions & 1 deletion scripts/update_docs.sh
Original file line number Diff line number Diff line change
@@ -25,7 +25,9 @@ if [[ "${TRAVIS_BRANCH}" == "master" ]] && \
elif [[ -n "${TRAVIS_TAG}" ]]; then
echo "Building new docs on a tag."
else
echo "Not on Travis, doing nothing."
echo "No docs to update for a new tag or merged commit on Travis."
echo "Verifying docs build successfully."
tox -e docs
exit
fi

141 changes: 141 additions & 0 deletions scripts/verify_included_modules.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Copyright 2016 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Check if all public modules are included in our docs."""


from __future__ import print_function

import os
import sys
import warnings

from sphinx.ext.intersphinx import fetch_inventory


BASE_DIR = os.path.abspath(
os.path.join(os.path.dirname(__file__), '..'))
DOCS_DIR = os.path.join(BASE_DIR, 'docs')
OBJECT_INVENTORY_RELPATH = os.path.join('_build', 'html', 'objects.inv')
IGNORED_PREFIXES = ('test_', '_')
IGNORED_MODULES = frozenset([
'gcloud.bigtable.client',
'gcloud.bigtable.cluster',
'gcloud.bigtable.column_family',
'gcloud.bigtable.happybase.connection',
'gcloud.bigtable.row',
'gcloud.bigtable.table',
'gcloud.datastore.demo.demo',
'gcloud.demo',
'gcloud.iterator',
'gcloud.storage.demo.demo',
'gcloud.streaming.buffered_stream',
'gcloud.streaming.exceptions',
'gcloud.streaming.http_wrapper',
'gcloud.streaming.stream_slice',
'gcloud.streaming.transfer',
'gcloud.streaming.util',
])


class SphinxApp(object):
"""Mock app to interact with Sphinx helpers."""
warn = warnings.warn
srcdir = DOCS_DIR


def is_valid_module(filename):
"""Determines if a filename is a valid Python module.
Assumes if is just the end of a path (i.e. does not contain
``os.path.sep``.
:type filename: string
:param filename: The name of a file.
:rtype: bool
:returns: Flag indicating if the filename is valid.
"""
if not filename.endswith('.py'):
return False
for prefix in IGNORED_PREFIXES:
if filename.startswith(prefix):
return False
return True


def get_public_modules(path, base_package=None):
"""Get list of all public modules relative to a path.
:type path: string
:param path: The path containing the python modules.
:type base_package: string
:param base_package: (Optional) A package to prepend in
front of the path.
:rtype: list
:returns: List of all modules found.
"""
result = []
for subdir, _, files in os.walk(path):
# Skip folders that start with _.
if any([part.startswith('_')
for part in subdir.split(os.path.sep)]):
continue
_, rel_dir = subdir.split(path)
rel_dir = rel_dir.lstrip(os.path.sep)
for filename in files:
if is_valid_module(filename):
mod_name, _ = os.path.splitext(filename)
rel_path = os.path.join(rel_dir, mod_name)
if base_package is not None:
rel_path = os.path.join(base_package, rel_path)
# Turn into a Python module rather than a file path.
result.append(rel_path.replace(os.path.sep, '.'))

return result


def main():
"""Main script to verify modules included."""
mock_uri = ''
inventory = fetch_inventory(SphinxApp, mock_uri,
OBJECT_INVENTORY_RELPATH)
sphinx_mods = set(inventory['py:module'].keys())

library_dir = os.path.join(BASE_DIR, 'gcloud')
public_mods = get_public_modules(library_dir,
base_package='gcloud')
public_mods = set(public_mods)

if not sphinx_mods <= public_mods:
message = ('Unexpected error. There were modules referenced by '
'Sphinx that are not among the public modules.')
print(message, file=sys.stderr)
sys.exit(1)

undocumented_mods = public_mods - sphinx_mods
# Remove ignored modules.
undocumented_mods -= IGNORED_MODULES
if undocumented_mods:
message_parts = ['Found undocumented public modules:']
message_parts.extend(['- ' + mod_name
for mod_name in sorted(undocumented_mods)])
print('\n'.join(message_parts), file=sys.stderr)
sys.exit(1)


if __name__ == '__main__':
main()
3 changes: 3 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -45,6 +45,7 @@ basepython =
commands =
python -c "import shutil; shutil.rmtree('docs/_build', ignore_errors=True)"
sphinx-build -W -b html -d docs/_build/doctrees docs docs/_build/html
python {toxinidir}/scripts/verify_included_modules.py
deps =
Sphinx
passenv = {[testenv:system-tests]passenv} SPHINX_RELEASE READTHEDOCS LOCAL_RTD
@@ -57,6 +58,7 @@ basepython = {[testenv:docs]basepython}
commands =
python -c "import shutil; shutil.rmtree('docs/_build_rtd', ignore_errors=True)"
sphinx-build -W -b html -d docs/_build_rtd/doctrees docs docs/_build_rtd/html
python {toxinidir}/scripts/verify_included_modules.py
deps = {[testenv:docs]deps}
passenv = {[testenv:docs]passenv}

@@ -75,6 +77,7 @@ deps =
pylint
unittest2
psutil
Sphinx
passenv = {[testenv:system-tests]passenv}

[testenv:system-tests]

0 comments on commit d56ea3d

Please sign in to comment.