Skip to content
Draft
15 changes: 15 additions & 0 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Configure test collection to skip doctests for modules that depend on sphinx
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if this is necessary. What about including numpydoc[default] in our test dependencies and then we can test everything?

Alternatively, what about marking the tests that require sphinx as expected fails when sphinx isn't available?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What about including numpydoc[default] in our test dependencies and then we can test everything?

This would work for CI but wouldn't work out-of-the-box for a development environment. I personally think there's value in being able to run only the tests (including doctests) for the non-sphinxy bits.

Copy link
Contributor

Choose a reason for hiding this comment

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

It might be worth using nox if we want that because now we are talking about needing to use two different virtual environments to run the tests like this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm -1 on more tooling for testing/environment management. All this change does is introduce importorskip-like behavior for doctests as well to ensure that the "full" test suite (i.e. including doctests) runs the correct tests whether or not sphinx is installed.

# when sphinx is not available in the environment.

try:
import sphinx

has_sphinx = True
except ImportError:
has_sphinx = False


collect_ignore = []

if not has_sphinx:
collect_ignore += ["numpydoc/numpydoc.py", "numpydoc/docscrape_sphinx.py"]
13 changes: 10 additions & 3 deletions numpydoc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,15 @@

from ._version import __version__

# NOTE: Determine whether sphinx is installed with an explicit import.
# If so, define the setup function for registering the numpydoc extension;
# otherwise skip this step.
try:
import sphinx

def setup(app, *args, **kwargs):
from .numpydoc import setup
def setup(app, *args, **kwargs):
from .numpydoc import setup

return setup(app, *args, **kwargs)
return setup(app, *args, **kwargs)
except ModuleNotFoundError:
pass
13 changes: 13 additions & 0 deletions numpydoc/_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import re


def _clean_text_signature(sig):
if sig is None:
return None
start_pattern = re.compile(r"^[^(]*\(")
start, end = start_pattern.search(sig).span()
start_sig = sig[start:end]
sig = sig[end:-1]
sig = re.sub(r"^\$(self|module|type)(,\s|$)", "", sig, count=1)
sig = re.sub(r"(^|(?<=,\s))/,\s\*", "*", sig, count=1)
return start_sig + sig + ")"
2 changes: 1 addition & 1 deletion numpydoc/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from pathlib import Path
from typing import List

from .docscrape_sphinx import get_doc_object
from .docscrape import get_doc_object
from .hooks import utils, validate_docstrings
from .validate import ERROR_MSGS, Validator, validate

Expand Down
2 changes: 1 addition & 1 deletion numpydoc/docscrape.py
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@ def dedent_lines(lines):


class FunctionDoc(NumpyDocString):
def __init__(self, func, role="func", doc=None, config=None):
def __init__(self, func, role=None, doc=None, config=None):
self._f = func
self._role = role # e.g. "func" or "meth"

Expand Down
13 changes: 1 addition & 12 deletions numpydoc/numpydoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from sphinx.util import logging

from . import __version__
from ._utils import _clean_text_signature
from .docscrape_sphinx import get_doc_object
from .validate import get_validation_checks, validate
from .xref import DEFAULT_LINKS
Expand Down Expand Up @@ -301,18 +302,6 @@ def mangle_signature(app: SphinxApp, what, name, obj, options, sig, retann):
return sig, ""


def _clean_text_signature(sig):
if sig is None:
return None
start_pattern = re.compile(r"^[^(]*\(")
start, end = start_pattern.search(sig).span()
start_sig = sig[start:end]
sig = sig[end:-1]
sig = re.sub(r"^\$(self|module|type)(,\s|$)", "", sig, count=1)
sig = re.sub(r"(^|(?<=,\s))/,\s\*", "*", sig, count=1)
return start_sig + sig + ")"


def setup(app: SphinxApp, get_doc_object_=get_doc_object):
if not hasattr(app, "add_config_value"):
return None # probably called by nose, better bail out
Expand Down
6 changes: 5 additions & 1 deletion numpydoc/tests/hooks/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ def test_find_project_root(tmp_path, request, reason_file, files, expected_reaso
(tmp_path / reason_file).touch()

if files:
expected_dir = Path("/") if expected_reason == "file system root" else tmp_path
if expected_reason == "file system root":
expected_dir = Path(tmp_path.drive + tmp_path.root)
else:
expected_dir = tmp_path

for file in files:
(tmp_path / file).touch()
else:
Expand Down
13 changes: 13 additions & 0 deletions numpydoc/tests/hooks/test_validate_hook.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Test the numpydoc validate pre-commit hook."""

import inspect
import sys
from pathlib import Path

import pytest
Expand Down Expand Up @@ -63,6 +64,8 @@ def test_validate_hook(example_module, config, capsys):
numpydoc/tests/hooks/example_module.py:30: GL08 The object does not have a docstring
"""
)
if sys.platform == "win32":
expected = expected.replace("/", "\\")

return_code = run_hook([example_module], config=config)
assert return_code == 1
Expand Down Expand Up @@ -90,6 +93,8 @@ def test_validate_hook_with_ignore(example_module, capsys):
numpydoc/tests/hooks/example_module.py:30: GL08 The object does not have a docstring
"""
)
if sys.platform == "win32":
expected = expected.replace("/", "\\")

return_code = run_hook([example_module], ignore=["ES01", "SA01", "EX01"])

Expand Down Expand Up @@ -133,6 +138,8 @@ def test_validate_hook_with_toml_config(example_module, tmp_path, capsys):
numpydoc/tests/hooks/example_module.py:30: GL08 The object does not have a docstring
"""
)
if sys.platform == "win32":
expected = expected.replace("/", "\\")

return_code = run_hook([example_module], config=tmp_path)
assert return_code == 1
Expand Down Expand Up @@ -168,6 +175,8 @@ def test_validate_hook_with_setup_cfg(example_module, tmp_path, capsys):
numpydoc/tests/hooks/example_module.py:30: GL08 The object does not have a docstring
"""
)
if sys.platform == "win32":
expected = expected.replace("/", "\\")

return_code = run_hook([example_module], config=tmp_path)
assert return_code == 1
Expand Down Expand Up @@ -209,6 +218,8 @@ def test_validate_hook_exclude_option_pyproject(example_module, tmp_path, capsys
numpydoc/tests/hooks/example_module.py:30: GL08 The object does not have a docstring
"""
)
if sys.platform == "win32":
expected = expected.replace("/", "\\")

return_code = run_hook([example_module], config=tmp_path)
assert return_code == 1
Expand Down Expand Up @@ -242,6 +253,8 @@ def test_validate_hook_exclude_option_setup_cfg(example_module, tmp_path, capsys
numpydoc/tests/hooks/example_module.py:17: PR07 Parameter "*args" has no description
"""
)
if sys.platform == "win32":
expected = expected.replace("/", "\\")

return_code = run_hook([example_module], config=tmp_path)
assert return_code == 1
Expand Down
Loading