diff --git a/CHANGES.rst b/CHANGES.rst index 1bba72b..8ee7331 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -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) diff --git a/docs/index.rst b/docs/index.rst index 481c8ea..4b2e102 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -9,7 +9,7 @@ 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 @@ -17,6 +17,8 @@ The extension is also available through conda package management system. It can conda install -c astropy sphinx-automodapi + + .. _quickstart: Quick start @@ -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. diff --git a/setup.cfg b/setup.cfg index 861c629..1db3624 100644 --- a/setup.cfg +++ b/setup.cfg @@ -20,7 +20,7 @@ classifiers = zip_safe = False packages = find: install_requires = - sphinx>=1.3 + sphinx>=1.7 [options.extras_require] test = diff --git a/sphinx_automodapi/autodoc_enhancements.py b/sphinx_automodapi/autodoc_enhancements.py index 41b8c9d..e32f00a 100644 --- a/sphinx_automodapi/autodoc_enhancements.py +++ b/sphinx_automodapi/autodoc_enhancements.py @@ -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: @@ -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} diff --git a/sphinx_automodapi/automodapi.py b/sphinx_automodapi/automodapi.py index 8f780ac..aad1ec1 100644 --- a/sphinx_automodapi/automodapi.py +++ b/sphinx_automodapi/automodapi.py @@ -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__ = [] @@ -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 @@ -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] @@ -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) diff --git a/sphinx_automodapi/automodsumm.py b/sphinx_automodapi/automodsumm.py index b89b9cb..61525eb 100644 --- a/sphinx_automodapi/automodsumm.py +++ b/sphinx_automodapi/automodsumm.py @@ -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'] @@ -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 = [] @@ -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) @@ -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 @@ -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 @@ -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)) @@ -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 @@ -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) @@ -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: @@ -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: diff --git a/sphinx_automodapi/tests/helpers.py b/sphinx_automodapi/tests/helpers.py index a1fdbb8..01b3510 100644 --- a/sphinx_automodapi/tests/helpers.py +++ b/sphinx_automodapi/tests/helpers.py @@ -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'] -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) @@ -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) diff --git a/sphinx_automodapi/tests/test_cases.py b/sphinx_automodapi/tests/test_cases.py index 306e885..0e3583c 100644 --- a/sphinx_automodapi/tests/test_cases.py +++ b/sphinx_automodapi/tests/test_cases.py @@ -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 = { @@ -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) diff --git a/sphinx_automodapi/utils.py b/sphinx_automodapi/utils.py index a0769b4..0ce8997 100644 --- a/sphinx_automodapi/utils.py +++ b/sphinx_automodapi/utils.py @@ -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() diff --git a/tox.ini b/tox.ini index f96e5c7..216d70e 100644 --- a/tox.ini +++ b/tox.ini @@ -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 @@ -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