diff --git a/.gitignore b/.gitignore
index 8f9b3ad..78caebd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@
*.so
*.pyd
__pycache__
+.vimsession
# Ignore .c files by default to avoid including generated code. If you want to
# add a non-generated .c extension, use `git add -f filename.c`.
diff --git a/README.rst b/README.rst
index 48c0f11..1be3b0d 100644
--- a/README.rst
+++ b/README.rst
@@ -9,6 +9,15 @@ available as a standalone package since it can be used for any other
package. The documentation can be found on
`ReadTheDocs `_.
+Proplot modifications
+---------------------
+I forked this repo for use with my `proplot `__ project and added the following features:
+
+* Skip over class methods that are public, but do *not* have their own ``__doc__`` attributes. This prevents inheriting and displaying documentation from external projects, namely matplotlib.
+* Include ``__getitem__``, ``__getattr__``, ``__setitem__``, and ``__setattr__`` in the list of builtin methods that are *not* ignored by the documentation generator. I use these to document some dictionary/list subclasses.
+* Give class methods and attributes their own stub pages, instead of putting all class methods and attributes on a single page. This also required adding the new files to ``env.found_docs`` and reordering the event hooks in ``automodsumm.py`` so that ``sphinx_automodapi`` is called before ``autosummary``. This way ``autosummary`` sees the new class pages and can build the appropriate stubs.
+
+
Running tests
-------------
diff --git a/hooks/README.md b/hooks/README.md
new file mode 100644
index 0000000..e6bf4b3
--- /dev/null
+++ b/hooks/README.md
@@ -0,0 +1,2 @@
+# Git hooks
+When you clone this repo, copy the `post-commit` script to `.git/hooks`. This hook tags the commit with a version number if the version string in `__init__.py` was changed.
diff --git a/hooks/post-commit b/hooks/post-commit
new file mode 100755
index 0000000..b794c25
--- /dev/null
+++ b/hooks/post-commit
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+#-----------------------------------------------------------------------------#
+# Post commit hook that looks for __version__ variable in __init__.py file,
+# compares it to the current tag, and updates the commit if the __version__ was
+# also updated. Copy to .git/hooks/post-commit to add this to any project.
+# See also: https://stackoverflow.com/a/27332476/4970632
+# See also: https://stackoverflow.com/a/46972376/4970632
+# This is currently very lightweight and assumes workflow where users
+# manually increment tag number, which is probably appropriate
+#-----------------------------------------------------------------------------#
+# Helper
+raise() {
+ echo "Error: $@"
+ exit 1
+}
+
+# Bail if we are in middle of rebase
+base=$(git rev-parse --show-toplevel)
+[ $? -ne 0 ] && raise "Not in git repository."
+[ -d $base/.git/rebase-merge ] && exit 0
+
+# Get head dir
+init=($(git ls-files | grep __init__.py | grep -v 'tests'))
+[ ${#init[@]} -eq 0 ] && raise "__init__.py not found."
+[ ${#init[@]} -gt 1 ] && raise "Multiple candidates for __init__.py: ${init[@]}"
+
+# Get version string
+version=$(cat $init | grep -E '^version|^__version')
+[ -z "$version" ] && raise "$init version string not found."
+[ $(echo "$version" | wc -l) -gt 1 ] && raise "Ambiguous version string in $init."
+version=$(echo "$version" | awk -F"['\"]" '{print $2}') # first string on line
+
+# Prompt user action
+# NOTE: Currently git suppresses interactivity but that's fine, just means
+# default action of adding tag is taken
+tag=$(git describe --tags $(git rev-list --tags --max-count=1))
+if [ $? -ne 0 ] || [ "$tag" != "v$version" ]; then
+ while true; do
+ read -r -p "Increment tag from $tag --> v$version? ([y]/n) " response
+ if [ -n "$response" ] && ! [[ "$response" =~ ^[NnYy]$ ]]; then
+ echo "Invalid response."
+ continue # invalid, so try again
+ fi
+ if ! [[ "$response" =~ ^[Nn]$ ]]; then
+ git tag "v$version"
+ [ $? -eq 0 ] && echo "Incremented tag from $tag --> v$version"
+ fi
+ break
+ done
+fi
diff --git a/setup.cfg b/setup.cfg
index 1db3624..27197c3 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -3,8 +3,8 @@ name = sphinx-automodapi
version = attr:sphinx_automodapi.__version__
description = Sphinx extension for auto-generating API documentation for entire modules
long_description = file:README.rst
-author = The Astropy Developers
-author_email = astropy.team@gmail.com
+author = Repo from The Astropy Developers, forked by Luke Davis
+author_email = astropy.team@gmail.com, lukelbd@gmail.com
license = BSD 3-Clause License
url = http://astropy.org
classifiers =
diff --git a/sphinx_automodapi/__init__.py b/sphinx_automodapi/__init__.py
index d5b0ac1..cd40119 100644
--- a/sphinx_automodapi/__init__.py
+++ b/sphinx_automodapi/__init__.py
@@ -1 +1 @@
-__version__ = '0.13.dev0'
+__version__ = '0.6.proplot-mods'
diff --git a/sphinx_automodapi/automodapi.py b/sphinx_automodapi/automodapi.py
index aad1ec1..a4ddadb 100644
--- a/sphinx_automodapi/automodapi.py
+++ b/sphinx_automodapi/automodapi.py
@@ -434,7 +434,7 @@ def setup(app):
from . import automodsumm
app.setup_extension(automodsumm.__name__)
- app.connect('source-read', process_automodapi)
+ app.connect('source-read', process_automodapi, priority=100)
app.add_config_value('automodapi_inheritance_diagram', True, True)
app.add_config_value('automodapi_toctreedirnm', 'api', True)
diff --git a/sphinx_automodapi/automodsumm.py b/sphinx_automodapi/automodsumm.py
index 61525eb..9a41b38 100644
--- a/sphinx_automodapi/automodsumm.py
+++ b/sphinx_automodapi/automodsumm.py
@@ -99,6 +99,11 @@ class members that are inherited from a base class. This value can be
__all__ = ['Automoddiagram', 'Automodsumm', 'automodsumm_to_autosummary_lines',
'generate_automodsumm_docs', 'process_automodsumm_generation']
+api_ignore_methods = []
+api_class_methods = [
+ '__init__', '__call__', # default
+ '__getitem__', '__setitem__', '__setattr__', '__getattr__', # custom
+ ]
def _str_list_converter(argument):
"""
@@ -263,13 +268,18 @@ def process_automodsumm_generation(app):
f.write(l)
f.write('\n')
+ logger = logging.getLogger(__name__)
for sfn, lines in zip(filestosearch, liness):
suffix = os.path.splitext(sfn)[1]
if len(lines) > 0:
- generate_automodsumm_docs(
+ new_files = generate_automodsumm_docs(
lines, sfn, app=app, builder=app.builder,
suffix=suffix, base_path=app.srcdir,
inherited_members=app.config.automodsumm_inherited_members)
+ # logger.info('New files: ' + ', '.join(os.path.basename(file)
+ # for file in new_files))
+ for f in new_files:
+ env.found_docs.add(env.path2doc(f))
# _automodsummrex = re.compile(r'^(\s*)\.\. automodsumm::\s*([A-Za-z0-9_.]+)\s*'
@@ -431,10 +441,17 @@ def generate_automodsumm_docs(lines, srcfn, app=None, suffix='.rst',
# Create our own templating environment - here we use Astropy's
# templates rather than the default autosummary templates, in order to
# allow docstrings to be shown for methods.
- template_dirs = [os.path.join(os.path.dirname(__file__), 'templates'),
- os.path.join(base_path, '_templates')]
+ local_dir = os.path.join(os.path.dirname(__file__), 'templates')
+ default_dir = os.path.join(base_path, '_templates')
+ template_dirs = [local_dir, default_dir]
if builder is not None:
# allow the user to override the templates
+ # also add to the templates_path
+ # TODO: messes up usage for some users?
+ local_dir_full = os.path.join(local_dir, 'autosummary_core')
+ templates_path = builder.config.templates_path
+ if local_dir_full not in templates_path:
+ templates_path.insert(0, local_dir_full)
template_loader = BuiltinTemplateLoader()
template_loader.init(builder, dirs=template_dirs)
else:
@@ -487,11 +504,11 @@ def generate_automodsumm_docs(lines, srcfn, app=None, suffix='.rst',
fn = os.path.join(path, name + suffix)
# skip it if it exists
+ # always add to new_files so we can add them to env.found_docs
+ new_files.append(fn)
if os.path.isfile(fn):
continue
- new_files.append(fn)
-
f = open(fn, 'w')
try:
@@ -512,7 +529,14 @@ def get_members_mod(obj, typ, include_public=[]):
typ = None -> all
"""
items = []
+ # Add back? Seems fragile to rely on automodapi to ignore
+ # random variables you declare or classes you import on the
+ # top-level module. Better to use the :skip: directive *or*
+ # omit objects from __all__.
for name in dir(obj):
+ # docstring = getattr(safe_getattr(obj, name), '__doc__')
+ # if not docstring and typ in ('function', 'class', 'exception'):
+ # continue
try:
documenter = get_documenter(app, safe_getattr(obj, name), obj)
except AttributeError:
@@ -523,7 +547,7 @@ def get_members_mod(obj, typ, include_public=[]):
if x in include_public or not x.startswith('_')]
return public, items
- def get_members_class(obj, typ, include_public=[],
+ def get_members_class(obj, typ, include_public=[], exclude_public=[],
include_base=False):
"""
typ = None -> all
@@ -552,19 +576,24 @@ def get_members_class(obj, typ, include_public=[],
else:
names = getattr(obj, '__dict__').keys()
+ # Modification here, only document something if it has a
+ # docstring! Do not inherit if empty, similar to
+ # :inherited-members: option
for name in names:
try:
documenter = get_documenter(app, safe_getattr(obj, name), obj)
except AttributeError:
continue
+ if documenter.objtype == 'method' and not getattr(safe_getattr(obj, name), '__doc__', ''):
+ continue
if typ is None or documenter.objtype == typ:
items.append(name)
elif typ == 'attribute' and documenter.objtype == 'property':
# In Sphinx 2.0 and above, properties have a separate
# objtype, but we treat them the same here.
items.append(name)
- public = [x for x in items
- if x in include_public or not x.startswith('_')]
+ public = [x for x in items if x not in exclude_public and
+ (x in include_public or not x.startswith('_'))]
return public, items
ns = {}
@@ -585,17 +614,16 @@ def get_members_class(obj, typ, include_public=[],
# use default value
include_base = inherited_members
- api_class_methods = ['__init__', '__call__']
ns['members'] = get_members_class(obj, None,
include_base=include_base)
ns['methods'], ns['all_methods'] = \
- get_members_class(obj, 'method', api_class_methods,
+ get_members_class(obj, 'method', api_class_methods, api_ignore_methods,
include_base=include_base)
ns['attributes'], ns['all_attributes'] = \
get_members_class(obj, 'attribute',
include_base=include_base)
- ns['methods'].sort()
- ns['attributes'].sort()
+ ns['methods'] = sorted(ns['methods'])
+ ns['attributes'] = sorted(ns['attributes'])
parts = name.split('.')
if doc.objtype in ('method', 'attribute'):
@@ -649,6 +677,7 @@ def get_members_class(obj, typ, include_public=[],
finally:
f.close()
+ return new_files
def setup(app):
@@ -663,7 +692,7 @@ def setup(app):
app.add_directive('automod-diagram', Automoddiagram)
app.add_directive('automodsumm', Automodsumm)
- app.connect('builder-inited', process_automodsumm_generation)
+ app.connect('builder-inited', process_automodsumm_generation, priority=100)
app.add_config_value('automodsumm_writereprocessed', False, True)
app.add_config_value('automodsumm_inherited_members', False, 'env')
diff --git a/sphinx_automodapi/templates/autosummary_core/class.rst b/sphinx_automodapi/templates/autosummary_core/class.rst
index 85105fa..e6994f8 100644
--- a/sphinx_automodapi/templates/autosummary_core/class.rst
+++ b/sphinx_automodapi/templates/autosummary_core/class.rst
@@ -20,6 +20,8 @@
.. rubric:: Attributes Summary
.. autosummary::
+ :toctree:
+ :template: base.rst
{% for item in attributes %}
~{{ name }}.{{ item }}
{%- endfor %}
@@ -33,6 +35,8 @@
.. rubric:: Methods Summary
.. autosummary::
+ :toctree:
+ :template: base.rst
{% for item in methods %}
~{{ name }}.{{ item }}
{%- endfor %}
@@ -40,26 +44,3 @@
{% endif %}
{% endblock %}
- {% block attributes_documentation %}
- {% if attributes %}
-
- .. rubric:: Attributes Documentation
-
- {% for item in attributes %}
- .. autoattribute:: {{ item }}
- {%- endfor %}
-
- {% endif %}
- {% endblock %}
-
- {% block methods_documentation %}
- {% if methods %}
-
- .. rubric:: Methods Documentation
-
- {% for item in methods %}
- .. automethod:: {{ item }}
- {%- endfor %}
-
- {% endif %}
- {% endblock %}