diff --git a/sphinx_automodapi/autodoc_enhancements.py b/sphinx_automodapi/autodoc_enhancements.py index 7721043..2ae4b24 100644 --- a/sphinx_automodapi/autodoc_enhancements.py +++ b/sphinx_automodapi/autodoc_enhancements.py @@ -1,6 +1,7 @@ """ Miscellaneous enhancements to help autodoc along. """ +import warnings from sphinx.ext.autodoc import AttributeDocumenter __all__ = [] @@ -58,7 +59,13 @@ def type_object_attrgetter(obj, attr, *defargs): return base.__dict__[attr] break - return getattr(obj, attr, *defargs) + # In some cases, getting attributes with getattr can lead to warnings, e.g. + # deprecation warnings (this is not normally the case with methods and + # regular properties since we don't execute them but using getattr does run + # the code inside those properties, so we filter out any warnings. + with warnings.catch_warnings(record=False): + warnings.simplefilter('ignore') + return getattr(obj, attr, *defargs) def setup(app): diff --git a/sphinx_automodapi/automodsumm.py b/sphinx_automodapi/automodsumm.py index 70e611b..1f61201 100644 --- a/sphinx_automodapi/automodsumm.py +++ b/sphinx_automodapi/automodsumm.py @@ -88,6 +88,7 @@ class members that are inherited from a base class. This value can be import os import re import io +import warnings from sphinx.util import logging from sphinx.ext.autosummary import Autosummary @@ -201,7 +202,12 @@ def get_items(self, names): self.bridge.genopt['imported-members'] = True except AttributeError: # Sphinx < 4.0 self.genopt['imported-members'] = True - return Autosummary.get_items(self, names) + # Autosummary.get_items relies on getattr to get attributes from classes. + # In some cases, getting attributes with getattr can lead to warnings, e.g. + # deprecation warnings, so we filter out any warnings. + with warnings.catch_warnings(record=False): + warnings.simplefilter('ignore') + return Autosummary.get_items(self, names) # <-------------------automod-diagram stuff-----------------------------------> @@ -469,7 +475,10 @@ def generate_automodsumm_docs(lines, srcfn, app=None, suffix='.rst', ensuredir(path) try: - import_by_name_values = import_by_name(name) + import warnings + with warnings.catch_warnings(record=False): + warnings.simplefilter('ignore') + import_by_name_values = import_by_name(name) except ImportError as e: logger.warning('[automodsumm] failed to import %r: %s' % (name, e)) continue diff --git a/sphinx_automodapi/tests/cases/class_with_property_warning/README.md b/sphinx_automodapi/tests/cases/class_with_property_warning/README.md new file mode 100644 index 0000000..a942693 --- /dev/null +++ b/sphinx_automodapi/tests/cases/class_with_property_warning/README.md @@ -0,0 +1 @@ +Documenting a module with a class that has a non-standard property that emits a warning diff --git a/sphinx_automodapi/tests/cases/class_with_property_warning/input/index.rst b/sphinx_automodapi/tests/cases/class_with_property_warning/input/index.rst new file mode 100644 index 0000000..955b233 --- /dev/null +++ b/sphinx_automodapi/tests/cases/class_with_property_warning/input/index.rst @@ -0,0 +1 @@ +.. automodapi:: sphinx_automodapi.tests.example_module.class_with_property_warning diff --git a/sphinx_automodapi/tests/cases/class_with_property_warning/output/api/sphinx_automodapi.tests.example_module.class_with_property_warning.Camelot.rst b/sphinx_automodapi/tests/cases/class_with_property_warning/output/api/sphinx_automodapi.tests.example_module.class_with_property_warning.Camelot.rst new file mode 100644 index 0000000..a053905 --- /dev/null +++ b/sphinx_automodapi/tests/cases/class_with_property_warning/output/api/sphinx_automodapi.tests.example_module.class_with_property_warning.Camelot.rst @@ -0,0 +1,19 @@ +Camelot +======= + +.. currentmodule:: sphinx_automodapi.tests.example_module.class_with_property_warning + +.. autoclass:: Camelot + :show-inheritance: + + .. rubric:: Attributes Summary + + .. autosummary:: + + ~Camelot.place + ~Camelot.silly + + .. rubric:: Attributes Documentation + + .. autoattribute:: place + .. autoattribute:: silly diff --git a/sphinx_automodapi/tests/cases/class_with_property_warning/output/index.rst.automodapi b/sphinx_automodapi/tests/cases/class_with_property_warning/output/index.rst.automodapi new file mode 100644 index 0000000..0df1c3d --- /dev/null +++ b/sphinx_automodapi/tests/cases/class_with_property_warning/output/index.rst.automodapi @@ -0,0 +1,19 @@ + +sphinx_automodapi.tests.example_module.class_with_property_warning Module +------------------------------------------------------------------------- + +.. automodule:: sphinx_automodapi.tests.example_module.class_with_property_warning + +Classes +^^^^^^^ + +.. automodsumm:: sphinx_automodapi.tests.example_module.class_with_property_warning + :classes-only: + :toctree: api + +Class Inheritance Diagram +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. automod-diagram:: sphinx_automodapi.tests.example_module.class_with_property_warning + :private-bases: + :parts: 1 diff --git a/sphinx_automodapi/tests/cases/class_with_property_warning/output/index.rst.automodsumm b/sphinx_automodapi/tests/cases/class_with_property_warning/output/index.rst.automodsumm new file mode 100644 index 0000000..cb956df --- /dev/null +++ b/sphinx_automodapi/tests/cases/class_with_property_warning/output/index.rst.automodsumm @@ -0,0 +1,6 @@ +.. currentmodule:: sphinx_automodapi.tests.example_module.class_with_property_warning + +.. autosummary:: + :toctree: api + + Camelot diff --git a/sphinx_automodapi/tests/example_module/class_with_property_warning.py b/sphinx_automodapi/tests/example_module/class_with_property_warning.py new file mode 100644 index 0000000..15b1d4d --- /dev/null +++ b/sphinx_automodapi/tests/example_module/class_with_property_warning.py @@ -0,0 +1,29 @@ +import warnings + +__all__ = ['Camelot'] + + +class customproperty: + def __init__(self, getter): + self.getter = getter + + def __get__(self, instance, owner): + return self.getter(owner) + + + +class Camelot(object): + """ + A class where a property emits a warning + """ + + @customproperty + def silly(cls): + warnings.warn("It is VERY silly", UserWarning) + + @property + def place(self): + """ + Indeed. + """ + pass diff --git a/sphinx_automodapi/tests/test_cases.py b/sphinx_automodapi/tests/test_cases.py index 72f6140..64f3de0 100644 --- a/sphinx_automodapi/tests/test_cases.py +++ b/sphinx_automodapi/tests/test_cases.py @@ -8,6 +8,7 @@ import sys import glob import shutil +import warnings from itertools import product import pytest @@ -99,7 +100,11 @@ def test_run_full_case(tmpdir, case_dir, parallel): try: os.chdir(docs_dir) - status = build_main(argv=argv) + # Make sure there are no warnings - this is needed to catch warnings that + # Sphinx might not capture. + with warnings.catch_warnings(record=True) as record: + warnings.simplefilter('error') + status = build_main(argv=argv) finally: os.chdir(start_dir) diff --git a/tox.ini b/tox.ini index 8395008..5183ccd 100644 --- a/tox.ini +++ b/tox.ini @@ -6,6 +6,7 @@ requires = pip >= 18.0 [testenv] changedir = .tmp/{envname} deps = + jinja2<3 # to avoid a deprecation warning with old versions of sphinx sphinx17: sphinx==1.7.* sphinx18: sphinx==1.8.* sphinx20: sphinx==2.0.*