diff --git a/.github/workflows/misc.yml b/.github/workflows/misc.yml index 5317b3d811..1890488008 100644 --- a/.github/workflows/misc.yml +++ b/.github/workflows/misc.yml @@ -24,7 +24,7 @@ jobs: matrix: python-version: ["3.10"] install: ['pip'] - check: ['style', 'doc'] + check: ['style', 'doctest'] pip-flags: [''] depends: ['REQUIREMENTS'] env: diff --git a/doc-requirements.txt b/doc-requirements.txt index c934d76e6b..64830ca962 100644 --- a/doc-requirements.txt +++ b/doc-requirements.txt @@ -1,6 +1,7 @@ -# Requirements for building docs +# Auto-generated by tools/update_requirements.py -r requirements.txt -sphinx<3 +matplotlib >= 1.5.3 numpydoc +sphinx ~= 5.3 texext -matplotlib >=1.3.1 +tomli; python_version < "3.11" diff --git a/doc/source/conf.py b/doc/source/conf.py index cb8ad8292e..1e3d298fdc 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -23,7 +23,10 @@ from pathlib import Path from runpy import run_path -import toml +try: + import tomllib +except ImportError: + import tomli as tomllib # Check for external Sphinx extensions we depend on try: @@ -52,14 +55,15 @@ fobj.write(rel['long_description']) # Load metadata from setup.cfg -pyproject_dict = toml.load(Path("../../pyproject.toml")) -metadata = pyproject_dict["project"] +with open(Path("../../pyproject.toml"), 'rb') as fobj: + pyproject = tomllib.load(fobj) +authors = pyproject["project"]["authors"][0] # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', - #'sphinx.ext.intersphinx', + 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.mathjax', 'sphinx.ext.inheritance_diagram', @@ -69,9 +73,10 @@ 'matplotlib.sphinxext.plot_directive', ] -# the following doesn't work with sphinx < 1.0, but will make a separate -# sphinx-autogen run obsolete in the future -#autosummary_generate = True +# Autosummary always wants to use a `generated/` directory. +# We generate with `make api-stamp` +# This could change in the future +autosummary_generate = False # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -87,9 +92,7 @@ # General information about the project. project = u'NiBabel' -author_name = metadata["authors"][0]["name"] -author_email = metadata["authors"][0]["email"] -copyright = f"2006-2022, {author_name} <{author_email}>" +copyright = f"2006-2022, {authors['name']} <{authors['email']}>" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -269,7 +272,7 @@ # Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://docs.python.org/': None} +intersphinx_mapping = {'https://docs.python.org/3/': None} # Config of plot_directive plot_include_source = True diff --git a/doc/source/devel/biaps/biap_0003.rst b/doc/source/devel/biaps/biap_0003.rst index e409a5243f..3b4bdad24e 100644 --- a/doc/source/devel/biaps/biap_0003.rst +++ b/doc/source/devel/biaps/biap_0003.rst @@ -199,8 +199,8 @@ The base level header will usually also have image metadata fields giving information about the whole image. A field is an "image metadata field" if it is defined at the top level of the header. For example:: ->>> hdr = dict(nipy_header_version='1.0', -... Manufacturer="SIEMENS") + >>> hdr = dict(nipy_header_version='1.0', + ... Manufacturer="SIEMENS") All image metadata fields are optional. @@ -635,7 +635,7 @@ Use case ^^^^^^^^ When doing motion correction on a 4D image, we calculate the required affine -transformation from |--| say |--| the second image to the first image; the +transformation from, say, the second image to the first image; the third image to the first image; etc. If there are N volumes in the 4D image, we would need to store N-1 affine transformations. If we have registered to the mean volume of the volume series instead of one of the volumes in the diff --git a/doc/source/devel/biaps/biap_0004.rst b/doc/source/devel/biaps/biap_0004.rst index b88dd3b779..d8ac1569af 100644 --- a/doc/source/devel/biaps/biap_0004.rst +++ b/doc/source/devel/biaps/biap_0004.rst @@ -221,6 +221,7 @@ Improving access to varying meta data through the Nifti Currently, when accessing varying meta data through the `get_meta` method you can only get one value at a time:: + >>> echo_times = [nii.get_meta('EchoTime', (0, 0, 0, idx)) for idx in xrange(data.shape[-1])] diff --git a/doc/source/devel/biaps/biap_0006.rst b/doc/source/devel/biaps/biap_0006.rst index 673318192f..ad4a0f9b8d 100644 --- a/doc/source/devel/biaps/biap_0006.rst +++ b/doc/source/devel/biaps/biap_0006.rst @@ -193,7 +193,7 @@ In NIfTI: We saw above that the MGH format refers to a volume (in our sense) as a *frame*. ECAT has the same usage - a frame is a 3D volume. The fmristat -software uses frame in the same sense |--| e.g. `line 32 of example.m +software uses frame in the same sense, e.g., `line 32 of example.m `_. Unfortunately DICOM appears to use "frame" to mean a 2D slice. For example, diff --git a/doc/source/devel/devdiscuss.rst b/doc/source/devel/devdiscuss.rst index d93fd54a99..c864928d60 100644 --- a/doc/source/devel/devdiscuss.rst +++ b/doc/source/devel/devdiscuss.rst @@ -22,3 +22,7 @@ progress. spm_use modified_images data_pkg_design + data_pkg_discuss + data_pkg_uses + scaling + bv_formats diff --git a/doc/source/devel/image_design.rst b/doc/source/devel/image_design.rst index 46e7b5b4db..4aa0b18a76 100644 --- a/doc/source/devel/image_design.rst +++ b/doc/source/devel/image_design.rst @@ -1,3 +1,5 @@ +:orphan: + ######################## The nibabel image object ######################## diff --git a/doc/source/installing_data.rst b/doc/source/installing_data.rst index daab142c7a..c1b335fd02 100644 --- a/doc/source/installing_data.rst +++ b/doc/source/installing_data.rst @@ -1,3 +1,5 @@ +:orphan: + .. _installing-data: Installing data packages diff --git a/doc/source/old/ioimplementation.rst b/doc/source/old/ioimplementation.rst index 1d198c27cb..fd7914f467 100644 --- a/doc/source/old/ioimplementation.rst +++ b/doc/source/old/ioimplementation.rst @@ -1,5 +1,7 @@ .. -*- mode: rst -*- +:orphan: + ################################################## Relationship between images and io implementations ################################################## diff --git a/doc/tools/build_modref_templates.py b/doc/tools/build_modref_templates.py index 6ec6848579..007175a262 100755 --- a/doc/tools/build_modref_templates.py +++ b/doc/tools/build_modref_templates.py @@ -83,6 +83,7 @@ def abort(error): r'\.info.*$', r'\.pkg_info.*$', r'\.py3k.*$', + r'\._version.*$', ] docwriter.write_api_docs(outdir) docwriter.write_index(outdir, 'index', relative_to=outdir) diff --git a/nibabel/batteryrunners.py b/nibabel/batteryrunners.py index a860ba3778..fecff5c13b 100644 --- a/nibabel/batteryrunners.py +++ b/nibabel/batteryrunners.py @@ -20,6 +20,7 @@ To run checks only, and return problem report objects: +>>> from nibabel.batteryrunners import BatteryRunner, Report >>> def chk(obj, fix=False): # minimal check ... return obj, Report() >>> btrun = BatteryRunner((chk,)) diff --git a/nibabel/ecat.py b/nibabel/ecat.py index 54f600f147..3405a4210c 100644 --- a/nibabel/ecat.py +++ b/nibabel/ecat.py @@ -520,7 +520,7 @@ def __init__(self, hdr, mlist, fileobj): there is one subheader for each frame in the ecat file Parameters - ----------- + ---------- hdr : EcatHeader ECAT main header mlist : array shape (N, 4) diff --git a/nibabel/gifti/__init__.py b/nibabel/gifti/__init__.py index 54bfbd0ffa..5f3519e2c4 100644 --- a/nibabel/gifti/__init__.py +++ b/nibabel/gifti/__init__.py @@ -13,7 +13,6 @@ .. autosummary:: :toctree: ../generated - giftiio gifti """ diff --git a/nibabel/processing.py b/nibabel/processing.py index b7abfb8c75..6b1c2c0a3b 100644 --- a/nibabel/processing.py +++ b/nibabel/processing.py @@ -325,11 +325,13 @@ def conform(from_img, Using the default arguments, this function is meant to replicate most parts of FreeSurfer's ``mri_convert --conform`` command. Specifically, this function: + - Resamples data to ``output_shape`` - Resamples voxel sizes to ``voxel_size`` - Reorients to RAS (``mri_convert --conform`` reorients to LIA) Unlike ``mri_convert --conform``, this command does not: + - Transform data to range [0, 255] - Cast to unsigned eight-bit integer diff --git a/nibabel/quaternions.py b/nibabel/quaternions.py index 1b8e8b0454..51192ca741 100644 --- a/nibabel/quaternions.py +++ b/nibabel/quaternions.py @@ -19,6 +19,7 @@ they are applied on the left of the vector. For example: >>> import numpy as np +>>> from nibabel.quaternions import quat2mat >>> q = [0, 1, 0, 0] # 180 degree rotation around axis 0 >>> M = quat2mat(q) # from this module >>> vec = np.array([1, 2, 3]).reshape((3,1)) # column vector diff --git a/nibabel/spatialimages.py b/nibabel/spatialimages.py index 09744d0149..4aa375155b 100644 --- a/nibabel/spatialimages.py +++ b/nibabel/spatialimages.py @@ -91,6 +91,7 @@ example, the Analyze data format needs an ``image`` and a ``header`` file type for storage: + >>> import numpy as np >>> import nibabel as nib >>> data = np.arange(24, dtype='f4').reshape((2,3,4)) >>> img = nib.AnalyzeImage(data, np.eye(4)) diff --git a/nibabel/tmpdirs.py b/nibabel/tmpdirs.py index 10b5ee78f5..f4874e7b4d 100644 --- a/nibabel/tmpdirs.py +++ b/nibabel/tmpdirs.py @@ -52,7 +52,7 @@ class InTemporaryDirectory(TemporaryDirectory): """ Create, return, and change directory to a temporary directory Notes - ------ + ----- As its name suggests, the class temporarily changes the working directory of the Python process, and this is not thread-safe. We suggest using it only for tests. diff --git a/pyproject.toml b/pyproject.toml index b5b6c0e52d..053e4c06cc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,8 +25,7 @@ classifiers = [ "Topic :: Scientific/Engineering", ] # Version from versioneer -# optional-dependencies from setup.cfg (using ConfigParser features) -dynamic = ["version", "optional-dependencies"] +dynamic = ["version"] [project.urls] "Homepage" = "https://nipy.org/nibabel" @@ -45,6 +44,32 @@ nib-trk2tck = "nibabel.cmdline.trk2tck:main" nib-roi = "nibabel.cmdline.roi:main" parrec2nii = "nibabel.cmdline.parrec2nii:main" +[project.optional-dependencies] +dicom = ["pydicom >=1.0.0"] +dicomfs = ["nibabel[dicom]", "pillow"] +dev = ["gitpython", "twine"] +doc = [ + "matplotlib >= 1.5.3", + "numpydoc", + "sphinx ~= 5.3", + "texext", + "tomli; python_version < \"3.11\"", +] +minc2 = ["h5py"] +spm = ["scipy"] +style = ["flake8"] +test = [ + "coverage", + "pytest !=5.3.4", + "pytest-cov", + "pytest-doctestplus", + "pytest-httpserver", + "pytest-xdist", +] +zstd = ["pyzstd >= 0.14.3"] +doctest = ["nibabel[doc,test]"] +all = ["nibabel[dicomfs,dev,doc,minc2,spm,style,test,zstd]"] + [tool.setuptools] platforms = ["OS Independent"] provides = ["nibabel", "nisext"] diff --git a/setup.cfg b/setup.cfg index 336958c605..607771ddc4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,43 +1,3 @@ -[options.extras_require] -dicom = - pydicom >=1.0.0 -dicomfs = - %(dicom)s - pillow -dev = - gitpython - twine -doc = - matplotlib >= 1.5.3 - numpydoc - sphinx ~= 5.3 - texext - toml -minc2 = - h5py -spm = - scipy -style = - flake8 -test = - coverage - pytest !=5.3.4 - pytest-cov - pytest-doctestplus - pytest-httpserver - pytest-xdist -zstd = - pyzstd >= 0.14.3 -all = - %(dicomfs)s - %(dev)s - %(doc)s - %(minc2)s - %(spm)s - %(style)s - %(test)s - %(zstd)s - [flake8] max-line-length = 100 ignore = D100,D101,D102,D103,D104,D105,D200,D201,D202,D204,D205,D208,D209,D210,D300,D301,D400,D401,D403,E24,E121,E123,E126,E226,E266,E402,E704,E731,F821,I100,I101,I201,N802,N803,N804,N806,W503,W504,W605 diff --git a/tools/ci/check.sh b/tools/ci/check.sh index a96f0874a4..3cfc1e5530 100755 --- a/tools/ci/check.sh +++ b/tools/ci/check.sh @@ -16,9 +16,8 @@ export NIBABEL_DATA_DIR="$PWD/nibabel-data" if [ "${CHECK_TYPE}" == "style" ]; then # Run styles only on core nibabel code. flake8 nibabel -elif [ "${CHECK_TYPE}" == "doc" ]; then - cd doc - make html && make doctest +elif [ "${CHECK_TYPE}" == "doctest" ]; then + make -C doc html && make -C doc doctest elif [ "${CHECK_TYPE}" == "test" ]; then # Change into an innocuous directory and find tests from installation mkdir for_testing diff --git a/tools/update_requirements.py b/tools/update_requirements.py index b167438c6f..c624d9a8f8 100755 --- a/tools/update_requirements.py +++ b/tools/update_requirements.py @@ -11,10 +11,12 @@ pyproject_toml = repo_root / "pyproject.toml" reqs = repo_root / "requirements.txt" min_reqs = repo_root / "min-requirements.txt" +doc_reqs = repo_root / "doc-requirements.txt" with open(pyproject_toml, 'rb') as fobj: config = tomli.load(fobj) requirements = config["project"]["dependencies"] +doc_requirements = config["project"]["optional-dependencies"]["doc"] script_name = Path(__file__).relative_to(repo_root) @@ -27,3 +29,7 @@ # Write minimum requirements lines[1:-1] = [req.replace(">=", "==").replace("~=", "==") for req in requirements] min_reqs.write_text("\n".join(lines)) + +# Write documentation requirements +lines[1:-1] = ["-r requirements.txt"] + doc_requirements +doc_reqs.write_text("\n".join(lines))