Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Changes in sphinx-automodapi
-----------------

- Fixed compatibility with Sphinx 2.0 and later. [#86]
- The minimum sphinx version is now 1.7. [#88]


0.11 (2019-05-29)
Expand Down
12 changes: 11 additions & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ standalone package that can be used for any project.
Installation
------------

This extension requires Sphinx 1.3 or later, and can be installed with::
This extension requires Sphinx 1.7 or later, and can be installed with::

pip install sphinx-automodapi

The extension is also available through conda package management system. It can be installed with::

conda install -c astropy sphinx-automodapi



.. _quickstart:

Quick start
Expand Down Expand Up @@ -69,3 +71,11 @@ User guide

automodapi.rst
automodsumm.rst

Dependency Version Guidelines
-----------------------------

As a general guideline, automodapi dependencies (at the time of writing, just
Sphinx) aim to maintain compatibility with versions <= 2 years old. Dependencies
may be newer, however, if specific features become important to help automodapi
work better or be more maintainable.
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ classifiers =
zip_safe = False
packages = find:
install_requires =
sphinx>=1.3
sphinx>=1.7

[options.extras_require]
test =
Expand Down
63 changes: 7 additions & 56 deletions sphinx_automodapi/autodoc_enhancements.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
from sphinx.ext.autodoc import AttributeDocumenter, ModuleDocumenter
from sphinx.util.inspect import isdescriptor

from .utils import SPHINX_LT_15

__all__ = []

if sys.version_info[0] == 3:
Expand Down Expand Up @@ -73,66 +71,19 @@ def type_object_attrgetter(obj, attr, *defargs):
return getattr(obj, attr, *defargs)


if SPHINX_LT_15:
# Provided to work around a bug in Sphinx
# See https://github.com/sphinx-doc/sphinx/pull/1843
class AttributeDocumenter(AttributeDocumenter):
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
non_attr_types = cls.method_types + class_types + \
(MethodDescriptorType,)
isdatadesc = isdescriptor(member) and not \
isinstance(member, non_attr_types) and not \
type(member).__name__ == "instancemethod"
# That last condition addresses an obscure case of C-defined
# methods using a deprecated type in Python 3, that is not
# otherwise exported anywhere by Python
return isdatadesc or (not isinstance(parent, ModuleDocumenter) and
not inspect.isroutine(member) and
not isinstance(member, class_types))


def setup(app):
# Must have the autodoc extension set up first so we can override it
app.setup_extension('sphinx.ext.autodoc')
# Need to import this too since it re-registers all the documenter types
# =_=
import sphinx.ext.autosummary.generate

app.add_autodoc_attrgetter(type, type_object_attrgetter)

if sphinx.version_info < (1, 4, 2):
# this is a really ugly hack to supress a warning that sphinx 1.4
# generates when overriding an existing directive (which is *desired*
# behavior here). As of sphinx v1.4.2, this has been fixed:
# https://github.com/sphinx-doc/sphinx/issues/2451
# But we leave it in for 1.4.0/1.4.1 . But if the "needs_sphinx" is
# eventually updated to >= 1.4.2, this should be removed entirely (in
# favor of the line in the "else" clause)
_oldwarn = app._warning
_oldwarncount = app._warncount
try:
try:
# *this* is in a try/finally because we don't want to force six as
# a real dependency. In sphinx 1.4, six is a prerequisite, so
# there's no issue. But in older sphinxes this may not be true...
# but the inderlying warning is absent anyway so we let it slide.
from six import StringIO
app._warning = StringIO()
except ImportError:
pass
app.add_autodocumenter(AttributeDocumenter)
finally:
app._warning = _oldwarn
app._warncount = _oldwarncount
else:
suppress_warnigns_orig = app.config.suppress_warnings[:]
if 'app.add_directive' not in app.config.suppress_warnings:
app.config.suppress_warnings.append('app.add_directive')
try:
app.add_autodocumenter(AttributeDocumenter)
finally:
app.config.suppress_warnings = suppress_warnigns_orig
suppress_warnings_orig = app.config.suppress_warnings[:]
if 'app.add_directive' not in app.config.suppress_warnings:
app.config.suppress_warnings.append('app.add_directive')
try:
app.add_autodocumenter(AttributeDocumenter)
finally:
app.config.suppress_warnings = suppress_warnings_orig

return {'parallel_read_safe': True,
'parallel_write_safe': True}
15 changes: 6 additions & 9 deletions sphinx_automodapi/automodapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,9 @@ class are included in the generated documentation. Defaults to ``False``.
import re
import sys

from .utils import SPHINX_LT_16, find_mod_objs
from sphinx.util import logging

from .utils import find_mod_objs

__all__ = []

Expand Down Expand Up @@ -199,12 +201,7 @@ def automodapi_replace(sourcestr, app, dotoctree=True, docname=None,
sphinx markup.
"""

if SPHINX_LT_16:
warn = app.warn
else:
from sphinx.util import logging
logger = logging.getLogger(__name__)
warn = logger.warning
logger = logging.getLogger(__name__)

spl = _automodapirex.split(sourcestr)
if len(spl) > 1: # automodsumm is in this document
Expand Down Expand Up @@ -282,7 +279,7 @@ def automodapi_replace(sourcestr, app, dotoctree=True, docname=None,
if len(hds) < 2:
msg = 'Not enough headings (got {0}, need 2), using default -^'
if warnings:
warn(msg.format(len(hds)), location)
logger.warning(msg.format(len(hds)), location)
hds = '-^'
h1, h2 = hds[:2]

Expand All @@ -291,7 +288,7 @@ def automodapi_replace(sourcestr, app, dotoctree=True, docname=None,
opsstrs = ','.join(unknownops)
msg = 'Found additional options ' + opsstrs + ' in automodapi.'
if warnings:
warn(msg, location)
logger.warning(msg, location)

ispkg, hascls, hasfuncs, hasother = _mod_info(
modnm, toskip, onlylocals=onlylocals)
Expand Down
47 changes: 13 additions & 34 deletions sphinx_automodapi/automodsumm.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,12 @@ class members that are inherited from a base class. This value can be
import re
import io

from sphinx.util import logging
from sphinx.ext.autosummary import Autosummary
from sphinx.ext.inheritance_diagram import InheritanceDiagram
from docutils.parsers.rst.directives import flag

from .utils import (SPHINX_LT_16, SPHINX_LT_17, find_mod_objs,
cleanup_whitespace)
from .utils import find_mod_objs, cleanup_whitespace

__all__ = ['Automoddiagram', 'Automodsumm', 'automodsumm_to_autosummary_lines',
'generate_automodsumm_docs', 'process_automodsumm_generation']
Expand Down Expand Up @@ -144,8 +144,8 @@ def run(self):
clsonly = 'classes-only' in self.options
varonly = 'variables-only' in self.options
if [clsonly, funconly, varonly].count(True) > 1:
self.warning('more than one of functions-only, classes-only, '
'or variables-only defined. Ignoring.')
self.warn('more than one of "functions-only", "classes-only", '
'or "variables-only" defined. Ignoring.')
clsonly = funconly = varonly = False

skipnames = []
Expand Down Expand Up @@ -310,12 +310,7 @@ def automodsumm_to_autosummary_lines(fn, app):

"""

if SPHINX_LT_16:
warn = app.warn
else:
from sphinx.util import logging
logger = logging.getLogger(__name__)
warn = logger.warning
logger = logging.getLogger(__name__)

fullfn = os.path.join(app.builder.env.srcdir, fn)

Expand Down Expand Up @@ -380,7 +375,7 @@ def automodsumm_to_autosummary_lines(fn, app):
msg = ('Defined more than one of functions-only, classes-only, '
'and variables-only. Skipping this directive.')
lnnum = sum([spl[j].count('\n') for j in range(i * 5 + 1)])
warn('[automodsumm] ' + msg, (fn, lnnum))
logger.warning('[automodsumm] ' + msg, (fn, lnnum))
continue

# Use the currentmodule directive so we can just put the local names
Expand Down Expand Up @@ -431,14 +426,7 @@ def generate_automodsumm_docs(lines, srcfn, app=None, suffix='.rst',

from .utils import find_autosummary_in_lines_for_automodsumm as find_autosummary_in_lines

if SPHINX_LT_16:
info = app.info
warn = app.warn
else:
from sphinx.util import logging
logger = logging.getLogger(__name__)
info = logger.info
warn = logger.warning
logger = logging.getLogger(__name__)

# Create our own templating environment - here we use Astropy's
# templates rather than the default autosummary templates, in order to
Expand All @@ -460,12 +448,12 @@ def generate_automodsumm_docs(lines, srcfn, app=None, suffix='.rst',
items = find_autosummary_in_lines(lines, filename=srcfn)
if len(items) > 0:
msg = '[automodsumm] {1}: found {0} automodsumm entries to generate'
info(msg.format(len(items), srcfn))
logger.info(msg.format(len(items), srcfn))

# gennms = [item[0] for item in items]
# if len(gennms) > 20:
# gennms = gennms[:10] + ['...'] + gennms[-10:]
# info('[automodsumm] generating autosummary for: ' + ', '.join(gennms))
# logger.info('[automodsumm] generating autosummary for: ' + ', '.join(gennms))

# remove possible duplicates
items = list(set(items))
Expand All @@ -487,7 +475,7 @@ def generate_automodsumm_docs(lines, srcfn, app=None, suffix='.rst',
try:
import_by_name_values = import_by_name(name)
except ImportError as e:
warn('[automodsumm] failed to import %r: %s' % (name, e))
logger.warning('[automodsumm] failed to import %r: %s' % (name, e))
continue

# if block to accommodate Sphinx's v1.2.2 and v1.2.3 respectively
Expand All @@ -508,10 +496,7 @@ def generate_automodsumm_docs(lines, srcfn, app=None, suffix='.rst',

try:

if SPHINX_LT_17:
doc = get_documenter(obj, parent)
else:
doc = get_documenter(app, obj, parent)
doc = get_documenter(app, obj, parent)

if template_name is not None:
template = template_env.get_template(template_name)
Expand All @@ -529,10 +514,7 @@ def get_members_mod(obj, typ, include_public=[]):
items = []
for name in dir(obj):
try:
if SPHINX_LT_17:
documenter = get_documenter(safe_getattr(obj, name), obj)
else:
documenter = get_documenter(app, safe_getattr(obj, name), obj)
documenter = get_documenter(app, safe_getattr(obj, name), obj)
except AttributeError:
continue
if typ is None or documenter.objtype == typ:
Expand Down Expand Up @@ -572,10 +554,7 @@ def get_members_class(obj, typ, include_public=[],

for name in names:
try:
if SPHINX_LT_17:
documenter = get_documenter(safe_getattr(obj, name), obj)
else:
documenter = get_documenter(app, safe_getattr(obj, name), obj)
documenter = get_documenter(app, safe_getattr(obj, name), obj)
except AttributeError:
continue
if typ is None or documenter.objtype == typ:
Expand Down
12 changes: 3 additions & 9 deletions sphinx_automodapi/tests/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,12 @@
import sys
from copy import deepcopy

from ..utils import SPHINX_LT_17
from sphinx.cmd.build import build_main

from . import cython_testpackage # noqa

__all__ = ['build_main', 'write_conf', 'run_sphinx_in_tmpdir']
__all__ = ['write_conf', 'run_sphinx_in_tmpdir']
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that OK to remove this from the namespace without a warning? I suppose yes as explicit imports still work.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only added this in that namespace in my last PR


if SPHINX_LT_17:
from sphinx import build_main
else:
from sphinx.cmd.build import build_main

intersphinx_mapping = {
'python': ('https://docs.python.org/{0}/'.format(sys.version_info[0]), None)
Expand Down Expand Up @@ -47,9 +44,6 @@ def run_sphinx_in_tmpdir(tmpdir, additional_conf={}, expect_error=False):
write_conf(tmpdir.join('conf.py').strpath, conf)

argv = ['-W', '-b', 'html', '.', '_build/html']
if SPHINX_LT_17:
# As of Sphinx 1.7, the first argument is now no longer ignored
argv.insert(0, 'sphinx-build')

try:
os.chdir(tmpdir.strpath)
Expand Down
9 changes: 1 addition & 8 deletions sphinx_automodapi/tests/test_cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,13 @@
from sphinx.util.osutil import ensuredir
from docutils.parsers.rst import directives, roles

from ..utils import SPHINX_LT_16, SPHINX_LT_17
from .helpers import build_main, write_conf

CASES_ROOT = os.path.join(os.path.dirname(__file__), 'cases')

CASES_DIRS = glob.glob(os.path.join(CASES_ROOT, '*'))

if SPHINX_LT_16 or os.environ.get('TRAVIS_OS_NAME', None) == 'osx':
PARALLEL = {False}
else:
PARALLEL = {False, True}
PARALLEL = {False, True}


intersphinx_mapping = {
Expand Down Expand Up @@ -99,9 +95,6 @@ def test_run_full_case(tmpdir, case_dir, parallel):
argv = ['-W', '-b', 'html', src_dir, '_build/html']
if parallel:
argv.insert(0, '-j 4')
if SPHINX_LT_17:
# As of Sphinx 1.7, the first argument is now no longer ignored
argv.insert(0, 'sphinx-build')

try:
os.chdir(docs_dir)
Expand Down
6 changes: 1 addition & 5 deletions sphinx_automodapi/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,9 @@
from sphinx import __version__
from sphinx.ext.autosummary.generate import find_autosummary_in_docstring

__all__ = ['SPHINX_LT_16', 'SPHINX_LT_17', 'cleanup_whitespace',
__all__ = ['cleanup_whitespace',
'find_mod_objs', 'find_autosummary_in_lines_for_automodsumm']

SPHINX_LT_15 = LooseVersion(__version__) < LooseVersion('1.5')
SPHINX_LT_16 = LooseVersion(__version__) < LooseVersion('1.6')
SPHINX_LT_17 = LooseVersion(__version__) < LooseVersion('1.7')

if sys.version_info[0] >= 3:
def iteritems(dictionary):
return dictionary.items()
Expand Down
9 changes: 1 addition & 8 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ envlist =
py37-test
py27-test-clocale
py37-test-clocale
py27-test-sphinx13
py35-test-sphinx14
py35-test-sphinx15
py36-test-sphinx16
py27-test-sphinx17
py36-test-sphinx17
py37-test-sphinx18
py37-test-sphinx20
Expand All @@ -18,10 +15,6 @@ requires = pip >= 18.0
[testenv]
changedir = .tmp/{envname}
deps =
sphinx13: sphinx==1.3.6
sphinx14: sphinx==1.4.9
sphinx15: sphinx==1.5.6
sphinx16: sphinx==1.6.7
sphinx17: sphinx==1.7.9
sphinx18: sphinx==1.8.5
sphinx20: sphinx==2.0.1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@astrofrog - unrelated to this PR, but why do we pin the version so precisely? This case no newer bugfix releases get tested (surely, it's only relevant for the latest release). What about setting sphinx==2.1.* instead? (I couldn't comment on the next line).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, does * work for pip?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, it does, we do that in ci-helpers, too :)

Copy link
Member Author

@eteq eteq Aug 12, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't want to do this in the commits I just pushed up since I'm not sure I fully understand the syntax here. So I'd say this could be a follow-on separate PR?

Expand Down