diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 000000000..c7779cb47 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,17 @@ +version: 2 + +sphinx: + configuration: docs/source/conf.py + +python: + install: + - requirements: docs/requirements.txt + +build: + os: ubuntu-22.04 + tools: + python: 3.10 + jobs: + pre_build: + # Run the apidoc command to generate the initial module files + - docs/run_apidoc.sh diff --git a/docs/Makefile b/docs/Makefile index d4bb2cbb9..d0c3cbf10 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -5,8 +5,8 @@ # from the environment for the first two. SPHINXOPTS ?= SPHINXBUILD ?= sphinx-build -SOURCEDIR = . -BUILDDIR = _build +SOURCEDIR = source +BUILDDIR = build # Put it first so that "make" without argument is like "make help". help: diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..2de521be8 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,14 @@ +HEXRD Documentation +=================== + +The HEXRD documentation utilizes sphinx along with sphinx-apidoc to +automatically generate documentation for all of the HEXRD packages. + +Manually created files may be added as well in either RST or Markdown format. +See the files in `source/users` as an example. + +To build the documentation locally, first install the dependencies in the +`requirements.txt` file, then run the `run_sphinx.sh` script. The HTML files +should be automatically generated and placed inside `build/html`. Open up +the `build/html/index.html` file in a web browser to view the generated +content. diff --git a/docs/README.rst b/docs/README.rst deleted file mode 100644 index 4a848d08c..000000000 --- a/docs/README.rst +++ /dev/null @@ -1,28 +0,0 @@ -HEXRD Documentation -------------------- - -This directory contains the majority of the documentation for HEXRD. - -Requirements ------------- -The following tools are needed to build the documentation: - -sphinx - -With `Anaconda `_-based Python -environments, you should be able to run:: - - conda install sphinx - -The documentation is built using ``make``: - -``make html`` - build the API and narrative documentation web pages. This -is the the default ``make`` target; running ``make`` is equivalent to -``make html``. - -``make html_noapi`` - same as ``make html``, but without auto-generating API -docs, the most time-consuming portion of the build process. - -``make pdf`` compiles the documentation into a redistributable pdf file. - -``make help`` provides information on all supported make targets. diff --git a/docs/autogen_api.py b/docs/autogen_api.py deleted file mode 100644 index 6c43a708f..000000000 --- a/docs/autogen_api.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python -"""Script to auto-generate our API docs. -""" -# stdlib imports -import os -import sys - -# local imports -sys.path.append(os.path.abspath('sphinxext')) -from apigen import ApiDocWriter - -#***************************************************************************** -if __name__ == '__main__': - pjoin = os.path.join - package = 'hexrd' - outdir = pjoin('source','api','generated') - docwriter = ApiDocWriter(package,rst_extension='.rst') - # You have to escape the . here because . is a special char for regexps. - # You must do make clean if you change this! - docwriter.package_skip_patterns += [r'\.wx$', - # Extensions are documented elsewhere. - #r'\.extensions', - #r'\.config\.profile', - # These should be accessed via nbformat.current - #r'\.nbformat\.v\d+', - ] - - # The inputhook* modules often cause problems on import, such as trying to - # load incompatible Qt bindings. It's easiest to leave them all out. The - # main API is in the inputhook module, which is documented. - docwriter.module_skip_patterns += [ r'\.new_detector', - r'\.new_crystallography', - #r'\.testing\.plugin', - # This just prints a deprecation msg: - #r'\.frontend$', - # Deprecated: - #r'\.core\.magics\.deprecated' - # We document this manually. - #r'\.utils\.py3compat', - # These are exposed by nbformat.current - #r'\.nbformat\.convert', - #r'\.nbformat\.validator', - # These are exposed in display - #r'\.core\.display', - #r'\.lib\.display', - ] - - # These modules import functions and classes from other places to expose - # them as part of the public API. They must have __all__ defined. The - # non-API modules they import from should be excluded by the skip patterns - # above. - docwriter.names_from__all__.update({ - #'IPython.nbformat.current', - #'IPython.display', - }) - - # Now, generate the outputs - docwriter.write_api_docs(outdir) - # Write index with .txt extension - we can include it, but Sphinx won't try - # to compile it - docwriter.write_index(outdir, 'gen.txt', - relative_to = pjoin('source','api') - ) - print('%d files written' % len(docwriter.written_modules)) diff --git a/docs/build.rst b/docs/build.rst deleted file mode 100644 index df87cc83d..000000000 --- a/docs/build.rst +++ /dev/null @@ -1,112 +0,0 @@ -HEXRD Build Instructions ------------------------- - -The preferred method for building the HEXRD package is via the conda -recipe located in ``/conda.recipe`` - -Requirements ------------- -The following tools are needed to build the package:: - - conda - conda-build - -With `Anaconda `_-based Python -environments, you should be able to run:: - - conda build conda.recipe/ - -Building --------- - -First, the dependencies for building an environment to run hexrd:: - - - cython - - fabio - - h5py - - matplotlib - - numba - - numpy - - progressbar >=2.3 - - python - - pyyaml - - setuptools - - scikit-image - - scikit-learn - - scipy - - wxpython - -If you will be running scripts of you own, I also strongly suggest adding spyder:: - - - spyder - -For example, to buid an environment to run hexrd v0.6.x, do the following:: - - conda create --name hexrd_0.6 cython h5py matplotlib numba numpy python=2.7 pyyaml setuptools scikit-image scikit-learn scipy spyder - conda install -c anaconda --name hexrd_0.6 wxpython - conda install -c anaconda --name hexrd_0.6 progressbar - conda activate hexrd_0.6 - - -Then install using setuptools:: - - python setup.py install - -Note, you will have to install fabio in the same environment using ``setup.py`` as well. -The procedure for building/installing with conda-build is as follows (*this is curently broken*) - -First, update conda and conda-build:: - - conda update conda - conda update conda-build - -Second, using ``conda-build``, purge previous builds (recommended, -not strictly required):: - - conda build purge - -In the event that you have previously run either -``python setup.py develop`` OR ``python setup.py install``, then first run -either:: - - python setup.py develop --uninstall - -or:: - - python setup.py install --record files.txt - cat files.txt | xargs rm -rf - -depending on how it was installed using ``distutils``. This will -remove any old builds/links. - -Note that the "nuclear option" for removing hexrd is as follows:: - - rm -rf /lib/python2.7/site-packages/hexrd* - rm /bin/hexrd* - -If you have installed ``hexrd`` in a specific conda environment, then -be sure to use the proper path to ``lib/`` under the root anaconda directory. - -Next, run ``conda-build``:: - - conda build conda.recipe/ --no-test - -Note that the ``--no-test`` flag supresses running the internal tests -until they are fixed (stay tuned...) - -Installation ------------- - -Findally, run ``conda install`` using the local package:: - - conda install hexrd=0.6 --use-local - -Conda should echo the proper version number package in the package -install list, which includes all dependencies. - -At this point, a check in a fresh terminal (outside the root hexrd -directory) and run:: - - hexrd --verison - -It should currently read ``hexrd 0.6.5`` diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index f9226a533..000000000 --- a/docs/conf.py +++ /dev/null @@ -1,55 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -import os -import sys -sys.path.insert(0, os.path.abspath('../')) - - -# -- Project information ----------------------------------------------------- - -project = 'hexrd' -copyright = '2020, Joel V. Bernier' -author = 'Joel V. Bernier' - -# The full version, including alpha/beta/rc tags -release = '0.7.6' - - -# -- General configuration --------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = 'alabaster' - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index daff7e7c4..000000000 --- a/docs/index.rst +++ /dev/null @@ -1,20 +0,0 @@ -.. hexrd documentation master file, created by - sphinx-quickstart on Thu Jun 4 17:06:52 2020. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to hexrd's documentation! -================================= - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index 2119f5109..000000000 --- a/docs/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=. -set BUILDDIR=_build - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 000000000..52e647622 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,4 @@ +sphinx +pygments +sphinx-rtd-theme +myst-parser diff --git a/docs/run_apidoc.sh b/docs/run_apidoc.sh new file mode 100755 index 000000000..029f40a27 --- /dev/null +++ b/docs/run_apidoc.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +SCRIPT_DIR=`dirname "$0"` +pushd . +cd $SCRIPT_DIR + +# sphinx-apidoc argument explanation: +# -d 1 - only use a depth of one for table of contents (TOC) +# -T - don't generate the modules.rst TOC file +# -e - put documentation for each module on its own page +# -f - overwrite previously existing files +# -o source/ - place the output files into the source directory +# ../hexrd - the path to the root source directory +# Extra arguments at the end are exclude patterns +sphinx-apidoc -d 1 -T -e -f -o source/ ../hexrd + +popd diff --git a/docs/run_sphinx.sh b/docs/run_sphinx.sh new file mode 100755 index 000000000..853ebad00 --- /dev/null +++ b/docs/run_sphinx.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +SCRIPT_DIR=`dirname "$0"` +pushd . +cd $SCRIPT_DIR + +# Clean up the current documentation +make clean html + +# Run the apidoc command +./run_apidoc.sh + +# Build the html files +make html + +popd diff --git a/docs/source/.gitignore b/docs/source/.gitignore new file mode 100644 index 000000000..6213b78a7 --- /dev/null +++ b/docs/source/.gitignore @@ -0,0 +1,2 @@ +# Other than index.rst, these are generated automatically +*.rst diff --git a/docs/source/api/index.rst b/docs/source/api/index.rst deleted file mode 100644 index 969ae1051..000000000 --- a/docs/source/api/index.rst +++ /dev/null @@ -1,5 +0,0 @@ -============= -The HEXRD API -============= - -.. .. include:: generated/gen.txt diff --git a/docs/source/conf.py b/docs/source/conf.py index 7f704a5b2..4d7928762 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,294 +1,62 @@ -# -*- coding: utf-8 -*- +# Configuration file for the Sphinx documentation builder. # -# hexrd documentation build configuration file, created by -# sphinx-quickstart on Fri Jul 11 09:23:49 2014. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys -import os +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html -ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' +# -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('../../')) -sys.path.insert(0, os.path.abspath('../sphinxext')) -# We load the ipython release info into a dict by explicit execution -from hexrd import __version__ -print(__version__) +import os +import sys -# -- General configuration ------------------------------------------------ +from hexrd.constants import __version__ as version + +sys.path.insert(0, os.path.abspath('../..')) + +# -- Project information ----------------------------------------------------- -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +project = 'hexrd' +copyright = '2023, LLNL, AFRL, CHESS, and Kitware' +author = 'Joel Bernier, Patrick Avery, Saransh Singh, Chris Harris, Rachel Lim, Darren Pagan, Donald Boyce, Brianna Major, John Tourtellot, Óscar Villellas Guillén, Ryan Rygg, Kelly Nygren, Paul Shade' + +# The full version, including alpha/beta/rc tags +release = version + +# -- General configuration ------------------------------------------------ # 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.autosummary', - #'sphinx.ext.doctest', - #'sphinx.ext.intersphinx', - 'sphinx.ext.todo', - 'sphinx.ext.coverage', - 'sphinx.ext.mathjax', - 'sphinx.ext.ifconfig', + # For automatic documentation of modules + 'sphinx.ext.autodoc', + # The nicer looking readthedocs theme + 'sphinx_rtd_theme', + # Support for markdown files + 'myst_parser', + # Add a link to the source code next to every documentation entry 'sphinx.ext.viewcode', - 'github' ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -if '+' in __version__: - todo_include_todos = True - rst_prolog = """ -.. note:: - - This documentation is for a development version of HEXRD. There may be - significant differences from the latest stable release. - -""" - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'hexrd' -copyright = u'2014, Joel Bernier, Darren Dale, et. al.' - -# ghissue config -github_project_url = "https://github.com/HEXRD/hexrd" - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = __version__.rsplit('-', 3)[0] -# The full version, including alpha/beta/rc tags. -release = __version__ - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -today_fmt = '%B %d, %Y' - # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] -# The reST default role (used for this markup: `text`) to use for all -# documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False - - -# -- Options for HTML output ---------------------------------------------- +# -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'default' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None +# +html_theme = 'sphinx_rtd_theme' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -#html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'hexrddoc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('index', 'hexrd.tex', u'hexrd Documentation', - u'Joel Bernier, Darren Dale, et. al.', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'hexrd', u'hexrd Documentation', - [u'Joel Bernier, Darren Dale, et. al.'], 1) -] - -# If true, show URL addresses after external links. -#man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'hexrd', u'hexrd Documentation', - u'Joel Bernier, Darren Dale, et. al.', 'hexrd', - 'X-ray diffraction analysis', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False - - -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/docs/source/index.rst b/docs/source/index.rst index 114f81c3f..be5f125ab 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -4,7 +4,7 @@ HEXRD Documentation .. only:: html - :Release: |release| + :Version: |version| :Date: |today| @@ -14,17 +14,10 @@ Contents: :maxdepth: 1 users/index - api/index + The HEXRD API dev/index - -.. todo:: - - Joel's explanation of hexrd's :download:`transforms <_static/transforms.pdf>` - needs to find a permanent home in the docs. - .. only:: html * :ref:`genindex` * :ref:`modindex` - * :ref:`search` diff --git a/docs/source/users/index.rst b/docs/source/users/index.rst index d655bfe29..44a1ffdcb 100644 --- a/docs/source/users/index.rst +++ b/docs/source/users/index.rst @@ -8,3 +8,4 @@ Contents: :maxdepth: 1 installation + transforms diff --git a/docs/source/users/transforms.md b/docs/source/users/transforms.md new file mode 100644 index 000000000..95bcf35d6 --- /dev/null +++ b/docs/source/users/transforms.md @@ -0,0 +1,4 @@ +HEXRD Transforms +================ + +See the [official documentation for HEXRD transforms](../_static/transforms.pdf). diff --git a/docs/sphinxext/apigen.py b/docs/sphinxext/apigen.py deleted file mode 100644 index 3be2ec2d2..000000000 --- a/docs/sphinxext/apigen.py +++ /dev/null @@ -1,454 +0,0 @@ -"""Attempt to generate templates for module reference with Sphinx - -XXX - we exclude extension modules - -To include extension modules, first identify them as valid in the -``_uri2path`` method, then handle them in the ``_parse_module`` script. - -We get functions and classes by parsing the text of .py files. -Alternatively we could import the modules for discovery, and we'd have -to do that for extension modules. This would involve changing the -``_parse_module`` method to work via import and introspection, and -might involve changing ``discover_modules`` (which determines which -files are modules, and therefore which module URIs will be passed to -``_parse_module``). - -NOTE: this is a modified version of a script originally shipped with the -PyMVPA project, which we've adapted for NIPY use. PyMVPA is an MIT-licensed -project.""" - -from __future__ import print_function - -# Stdlib imports -import ast -import inspect -import os -import re - -class Obj(object): - '''Namespace to hold arbitrary information.''' - def __init__(self, **kwargs): - for k, v in kwargs.items(): - setattr(self, k, v) - -class FuncClsScanner(ast.NodeVisitor): - """Scan a module for top-level functions and classes. - - Skips objects with an @undoc decorator, or a name starting with '_'. - """ - def __init__(self): - ast.NodeVisitor.__init__(self) - self.classes = [] - self.classes_seen = set() - self.functions = [] - - @staticmethod - def has_undoc_decorator(node): - return any(isinstance(d, ast.Name) and d.id == 'undoc' \ - for d in node.decorator_list) - - def visit_If(self, node): - if isinstance(node.test, ast.Compare) \ - and isinstance(node.test.left, ast.Name) \ - and node.test.left.id == '__name__': - return # Ignore classes defined in "if __name__ == '__main__':" - - self.generic_visit(node) - - def visit_FunctionDef(self, node): - if not (node.name.startswith('_') or self.has_undoc_decorator(node)) \ - and node.name not in self.functions: - self.functions.append(node.name) - - def visit_ClassDef(self, node): - if not (node.name.startswith('_') or self.has_undoc_decorator(node)) \ - and node.name not in self.classes_seen: - cls = Obj(name=node.name) - cls.has_init = any(isinstance(n, ast.FunctionDef) and \ - n.name=='__init__' for n in node.body) - self.classes.append(cls) - self.classes_seen.add(node.name) - - def scan(self, mod): - self.visit(mod) - return self.functions, self.classes - -# Functions and classes -class ApiDocWriter(object): - ''' Class for automatic detection and parsing of API docs - to Sphinx-parsable reST format''' - - # only separating first two levels - rst_section_levels = ['*', '=', '-', '~', '^'] - - def __init__(self, - package_name, - rst_extension='.rst', - package_skip_patterns=None, - module_skip_patterns=None, - names_from__all__=None, - ): - ''' Initialize package for parsing - - Parameters - ---------- - package_name : string - Name of the top-level package. *package_name* must be the - name of an importable package - rst_extension : string, optional - Extension for reST files, default '.rst' - package_skip_patterns : None or sequence of {strings, regexps} - Sequence of strings giving URIs of packages to be excluded - Operates on the package path, starting at (including) the - first dot in the package path, after *package_name* - so, - if *package_name* is ``sphinx``, then ``sphinx.util`` will - result in ``.util`` being passed for earching by these - regexps. If is None, gives default. Default is: - ['\.tests$'] - module_skip_patterns : None or sequence - Sequence of strings giving URIs of modules to be excluded - Operates on the module name including preceding URI path, - back to the first dot after *package_name*. For example - ``sphinx.util.console`` results in the string to search of - ``.util.console`` - If is None, gives default. Default is: - ['\.setup$', '\._'] - names_from__all__ : set, optional - Modules listed in here will be scanned by doing ``from mod import *``, - rather than finding function and class definitions by scanning the - AST. This is intended for API modules which expose things defined in - other files. Modules listed here must define ``__all__`` to avoid - exposing everything they import. - ''' - if package_skip_patterns is None: - package_skip_patterns = ['\\.tests$'] - if module_skip_patterns is None: - module_skip_patterns = ['\\.setup$', '\\._'] - self.package_name = package_name - self.rst_extension = rst_extension - self.package_skip_patterns = package_skip_patterns - self.module_skip_patterns = module_skip_patterns - self.names_from__all__ = names_from__all__ or set() - - def get_package_name(self): - return self._package_name - - def set_package_name(self, package_name): - ''' Set package_name - - >>> docwriter = ApiDocWriter('sphinx') - >>> import sphinx - >>> docwriter.root_path == sphinx.__path__[0] - True - >>> docwriter.package_name = 'docutils' - >>> import docutils - >>> docwriter.root_path == docutils.__path__[0] - True - ''' - # It's also possible to imagine caching the module parsing here - self._package_name = package_name - self.root_module = __import__(package_name) - self.root_path = self.root_module.__path__[0] - self.written_modules = None - - package_name = property(get_package_name, set_package_name, None, - 'get/set package_name') - - def _uri2path(self, uri): - ''' Convert uri to absolute filepath - - Parameters - ---------- - uri : string - URI of python module to return path for - - Returns - ------- - path : None or string - Returns None if there is no valid path for this URI - Otherwise returns absolute file system path for URI - - Examples - -------- - >>> docwriter = ApiDocWriter('sphinx') - >>> import sphinx - >>> modpath = sphinx.__path__[0] - >>> res = docwriter._uri2path('sphinx.builder') - >>> res == os.path.join(modpath, 'builder.py') - True - >>> res = docwriter._uri2path('sphinx') - >>> res == os.path.join(modpath, '__init__.py') - True - >>> docwriter._uri2path('sphinx.does_not_exist') - - ''' - if uri == self.package_name: - return os.path.join(self.root_path, '__init__.py') - path = uri.replace('.', os.path.sep) - path = path.replace(self.package_name + os.path.sep, '') - path = os.path.join(self.root_path, path) - # XXX maybe check for extensions as well? - if os.path.exists(path + '.py'): # file - path += '.py' - elif os.path.exists(os.path.join(path, '__init__.py')): - path = os.path.join(path, '__init__.py') - else: - return None - return path - - def _path2uri(self, dirpath): - ''' Convert directory path to uri ''' - relpath = dirpath.replace(self.root_path, self.package_name) - if relpath.startswith(os.path.sep): - relpath = relpath[1:] - return relpath.replace(os.path.sep, '.') - - def _parse_module(self, uri): - ''' Parse module defined in *uri* ''' - filename = self._uri2path(uri) - if filename is None: - # nothing that we could handle here. - return ([],[]) - with open(filename, 'rb') as f: - mod = ast.parse(f.read()) - return FuncClsScanner().scan(mod) - - def _import_funcs_classes(self, uri): - """Import * from uri, and separate out functions and classes.""" - ns = {} - exec('from %s import *' % uri, ns) - funcs, classes = [], [] - for name, obj in ns.items(): - if inspect.isclass(obj): - cls = Obj(name=name, has_init='__init__' in obj.__dict__) - classes.append(cls) - elif inspect.isfunction(obj): - funcs.append(name) - - return sorted(funcs), sorted(classes, key=lambda x: x.name) - - def find_funcs_classes(self, uri): - """Find the functions and classes defined in the module ``uri``""" - if uri in self.names_from__all__: - # For API modules which expose things defined elsewhere, import them - return self._import_funcs_classes(uri) - else: - # For other modules, scan their AST to see what they define - return self._parse_module(uri) - - def generate_api_doc(self, uri): - '''Make autodoc documentation template string for a module - - Parameters - ---------- - uri : string - python location of module - e.g 'sphinx.builder' - - Returns - ------- - S : string - Contents of API doc - ''' - # get the names of all classes and functions - functions, classes = self.find_funcs_classes(uri) - if not len(functions) and not len(classes): - #print ('WARNING: Empty -', uri) # dbg - return '' - - # Make a shorter version of the uri that omits the package name for - # titles - uri_short = re.sub(r'^%s\.' % self.package_name,'',uri) - - ad = '.. AUTO-GENERATED FILE -- DO NOT EDIT!\n\n' - - # Set the chapter title to read 'Module:' for all modules except for the - # main packages - if '.' in uri: - chap_title = 'Module: :mod:`' + uri_short + '`' - else: - chap_title = ':mod:`' + uri_short + '`' - ad += chap_title + '\n' + self.rst_section_levels[1] * len(chap_title) - - ad += '\n.. automodule:: ' + uri + '\n' - ad += '\n.. currentmodule:: ' + uri + '\n' - - if classes: - subhead = str(len(classes)) + (' Classes' if len(classes) > 1 else ' Class') - ad += '\n'+ subhead + '\n' + \ - self.rst_section_levels[2] * len(subhead) + '\n' - - for c in classes: - ad += '\n.. autoclass:: ' + c.name + '\n' - # must NOT exclude from index to keep cross-refs working - ad += ' :members:\n' \ - ' :show-inheritance:\n' - if c.has_init: - ad += '\n .. automethod:: __init__\n' - - if functions: - subhead = str(len(functions)) + (' Functions' if len(functions) > 1 else ' Function') - ad += '\n'+ subhead + '\n' + \ - self.rst_section_levels[2] * len(subhead) + '\n' - for f in functions: - # must NOT exclude from index to keep cross-refs working - ad += '\n.. autofunction:: ' + uri + '.' + f + '\n\n' - return ad - - def _survives_exclude(self, matchstr, match_type): - ''' Returns True if *matchstr* does not match patterns - - ``self.package_name`` removed from front of string if present - - Examples - -------- - >>> dw = ApiDocWriter('sphinx') - >>> dw._survives_exclude('sphinx.okpkg', 'package') - True - >>> dw.package_skip_patterns.append('^\\.badpkg$') - >>> dw._survives_exclude('sphinx.badpkg', 'package') - False - >>> dw._survives_exclude('sphinx.badpkg', 'module') - True - >>> dw._survives_exclude('sphinx.badmod', 'module') - True - >>> dw.module_skip_patterns.append('^\\.badmod$') - >>> dw._survives_exclude('sphinx.badmod', 'module') - False - ''' - if match_type == 'module': - patterns = self.module_skip_patterns - elif match_type == 'package': - patterns = self.package_skip_patterns - else: - raise ValueError('Cannot interpret match type "%s"' - % match_type) - # Match to URI without package name - L = len(self.package_name) - if matchstr[:L] == self.package_name: - matchstr = matchstr[L:] - for pat in patterns: - try: - pat.search - except AttributeError: - pat = re.compile(pat) - if pat.search(matchstr): - return False - return True - - def discover_modules(self): - ''' Return module sequence discovered from ``self.package_name`` - - - Parameters - ---------- - None - - Returns - ------- - mods : sequence - Sequence of module names within ``self.package_name`` - - Examples - -------- - >>> dw = ApiDocWriter('sphinx') - >>> mods = dw.discover_modules() - >>> 'sphinx.util' in mods - True - >>> dw.package_skip_patterns.append('\.util$') - >>> 'sphinx.util' in dw.discover_modules() - False - >>> - ''' - modules = [self.package_name] - # raw directory parsing - for dirpath, dirnames, filenames in os.walk(self.root_path): - # Check directory names for packages - root_uri = self._path2uri(os.path.join(self.root_path, - dirpath)) - for dirname in dirnames[:]: # copy list - we modify inplace - package_uri = '.'.join((root_uri, dirname)) - if (self._uri2path(package_uri) and - self._survives_exclude(package_uri, 'package')): - modules.append(package_uri) - else: - dirnames.remove(dirname) - # Check filenames for modules - for filename in filenames: - module_name = filename[:-3] - module_uri = '.'.join((root_uri, module_name)) - if (self._uri2path(module_uri) and - self._survives_exclude(module_uri, 'module')): - modules.append(module_uri) - return sorted(modules) - - def write_modules_api(self, modules,outdir): - # write the list - written_modules = [] - for m in modules: - api_str = self.generate_api_doc(m) - if not api_str: - continue - # write out to file - outfile = os.path.join(outdir, - m + self.rst_extension) - fileobj = open(outfile, 'wt') - fileobj.write(api_str) - fileobj.close() - written_modules.append(m) - self.written_modules = written_modules - - def write_api_docs(self, outdir): - """Generate API reST files. - - Parameters - ---------- - outdir : string - Directory name in which to store files - We create automatic filenames for each module - - Returns - ------- - None - - Notes - ----- - Sets self.written_modules to list of written modules - """ - if not os.path.exists(outdir): - os.mkdir(outdir) - # compose list of modules - modules = self.discover_modules() - self.write_modules_api(modules,outdir) - - def write_index(self, outdir, path='gen.rst', relative_to=None): - """Make a reST API index file from written files - - Parameters - ---------- - outdir : string - Directory to which to write generated index file - path : string - Filename to write index to - relative_to : string - path to which written filenames are relative. This - component of the written file path will be removed from - outdir, in the generated index. Default is None, meaning, - leave path as it is. - """ - if self.written_modules is None: - raise ValueError('No modules written') - # Get full filename path - path = os.path.join(outdir, path) - # Path written into index is relative to rootpath - if relative_to is not None: - relpath = outdir.replace(relative_to + os.path.sep, '') - else: - relpath = outdir - idx = open(path,'wt') - w = idx.write - w('.. AUTO-GENERATED FILE -- DO NOT EDIT!\n\n') - w('.. autosummary::\n' - ' :toctree: %s\n\n' % relpath) - for mod in self.written_modules: - w(' %s\n' % mod) - idx.close() diff --git a/docs/sphinxext/github.py b/docs/sphinxext/github.py deleted file mode 100644 index 92da665d1..000000000 --- a/docs/sphinxext/github.py +++ /dev/null @@ -1,156 +0,0 @@ -"""Define text roles for GitHub - -* ghissue - Issue -* ghpull - Pull Request -* ghuser - User - -Adapted from bitbucket example here: -https://bitbucket.org/birkenfeld/sphinx-contrib/src/tip/bitbucket/sphinxcontrib/bitbucket.py - -Authors -------- - -* Doug Hellmann -* Min RK -""" -# -# Original Copyright (c) 2010 Doug Hellmann. All rights reserved. -# - -from docutils import nodes, utils -from docutils.parsers.rst.roles import set_classes - -def make_link_node(rawtext, app, type, slug, options): - """Create a link to a github resource. - - :param rawtext: Text being replaced with link node. - :param app: Sphinx application context - :param type: Link type (issues, changeset, etc.) - :param slug: ID of the thing to link to - :param options: Options dictionary passed to role func. - """ - - try: - base = app.config.github_project_url - if not base: - raise AttributeError - if not base.endswith('/'): - base += '/' - except AttributeError as err: - raise ValueError('github_project_url configuration value is not set (%s)' % str(err)) - - ref = base + type + '/' + slug + '/' - set_classes(options) - prefix = "#" - if type == 'pull': - prefix = "PR " + prefix - node = nodes.reference(rawtext, prefix + utils.unescape(slug), refuri=ref, - **options) - return node - -def ghissue_role(name, rawtext, text, lineno, inliner, options={}, content=[]): - """Link to a GitHub issue. - - Returns 2 part tuple containing list of nodes to insert into the - document and a list of system messages. Both are allowed to be - empty. - - :param name: The role name used in the document. - :param rawtext: The entire markup snippet, with role. - :param text: The text marked with the role. - :param lineno: The line number where rawtext appears in the input. - :param inliner: The inliner instance that called us. - :param options: Directive options for customization. - :param content: The directive content for customization. - """ - - try: - issue_num = int(text) - if issue_num <= 0: - raise ValueError - except ValueError: - msg = inliner.reporter.error( - 'GitHub issue number must be a number greater than or equal to 1; ' - '"%s" is invalid.' % text, line=lineno) - prb = inliner.problematic(rawtext, rawtext, msg) - return [prb], [msg] - app = inliner.document.settings.env.app - #app.info('issue %r' % text) - if 'pull' in name.lower(): - category = 'pull' - elif 'issue' in name.lower(): - category = 'issues' - else: - msg = inliner.reporter.error( - 'GitHub roles include "ghpull" and "ghissue", ' - '"%s" is invalid.' % name, line=lineno) - prb = inliner.problematic(rawtext, rawtext, msg) - return [prb], [msg] - node = make_link_node(rawtext, app, category, str(issue_num), options) - return [node], [] - -def ghuser_role(name, rawtext, text, lineno, inliner, options={}, content=[]): - """Link to a GitHub user. - - Returns 2 part tuple containing list of nodes to insert into the - document and a list of system messages. Both are allowed to be - empty. - - :param name: The role name used in the document. - :param rawtext: The entire markup snippet, with role. - :param text: The text marked with the role. - :param lineno: The line number where rawtext appears in the input. - :param inliner: The inliner instance that called us. - :param options: Directive options for customization. - :param content: The directive content for customization. - """ - app = inliner.document.settings.env.app - #app.info('user link %r' % text) - ref = 'https://www.github.com/' + text - node = nodes.reference(rawtext, text, refuri=ref, **options) - return [node], [] - -def ghcommit_role(name, rawtext, text, lineno, inliner, options={}, content=[]): - """Link to a GitHub commit. - - Returns 2 part tuple containing list of nodes to insert into the - document and a list of system messages. Both are allowed to be - empty. - - :param name: The role name used in the document. - :param rawtext: The entire markup snippet, with role. - :param text: The text marked with the role. - :param lineno: The line number where rawtext appears in the input. - :param inliner: The inliner instance that called us. - :param options: Directive options for customization. - :param content: The directive content for customization. - """ - app = inliner.document.settings.env.app - #app.info('user link %r' % text) - try: - base = app.config.github_project_url - if not base: - raise AttributeError - if not base.endswith('/'): - base += '/' - except AttributeError as err: - raise ValueError('github_project_url configuration value is not set (%s)' % str(err)) - - ref = base + text - node = nodes.reference(rawtext, text[:6], refuri=ref, **options) - return [node], [] - - -def setup(app): - """Install the plugin. - - :param app: Sphinx application context. - """ - app.info('Initializing GitHub plugin') - app.add_role('ghissue', ghissue_role) - app.add_role('ghpull', ghissue_role) - app.add_role('ghuser', ghuser_role) - app.add_role('ghcommit', ghcommit_role) - app.add_config_value('github_project_url', None, 'env') - return -