From de74356bbf559e4c98a3829c9c266ef76e7af813 Mon Sep 17 00:00:00 2001 From: Pieter Holtzhausen Date: Thu, 30 Jun 2011 16:14:46 +0200 Subject: [PATCH 01/16] Added destination to Makefile and fixed doc system --- doc/Makefile | 30 +++++++++++++++--------------- doc/ext/numpydoc.py | 11 +++++++++-- doc/tools/apigen.py | 5 +++-- 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/doc/Makefile b/doc/Makefile index c09f9168..55c952df 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -10,7 +10,7 @@ PAPER = PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source - +DEST = build .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest help: @@ -29,7 +29,7 @@ help: @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: - -rm -rf build/* + -rm -rf $(DEST)/* api: mkdir -p source/api @@ -37,33 +37,33 @@ api: @echo "Build API docs finished." html: api - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) build/html + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(DEST)/html @echo @echo "Build finished. The HTML pages are in build/html." dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) build/dirhtml + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(DEST)/dirhtml @echo @echo "Build finished. The HTML pages are in build/dirhtml." pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) build/pickle + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(DEST)/pickle @echo @echo "Build finished; now you can process the pickle files." json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) build/json + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(DEST)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) build/htmlhelp + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(DEST)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in build/htmlhelp." qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) build/qthelp + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(DEST)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in build/qthelp, like this:" @@ -72,7 +72,7 @@ qthelp: @echo "# assistant -collectionFile build/qthelp/scikitsimage.qhc" devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) build/devhelp + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(DEST)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @@ -81,30 +81,30 @@ devhelp: @echo "# devhelp" latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) build/latex + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(DEST)/latex @echo - @echo "Build finished; the LaTeX files are in build/latex." + @echo "Build finished; the LaTeX files are in $(DEST)/latex." @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ "run these through (pdf)latex." latexpdf: latex - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) build/latex + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(DEST)/latex @echo "Running LaTeX files through pdflatex..." make -C build/latex all-pdf @echo "pdflatex finished; the PDF files are in build/latex." changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) build/changes + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(DEST)/changes @echo @echo "The overview file is in build/changes." linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) build/linkcheck + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(DEST)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in build/linkcheck/output.txt." doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) build/doctest + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(DEST)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in build/doctest/output.txt." diff --git a/doc/ext/numpydoc.py b/doc/ext/numpydoc.py index 707107da..6667c429 100644 --- a/doc/ext/numpydoc.py +++ b/doc/ext/numpydoc.py @@ -124,8 +124,15 @@ def get_directive(name): from docutils.parsers.rst import directives try: return directives.directive(name, None, None)[0] - except AttributeError: - pass + except AttributeError: + if "method" in name: + name = "automethod" + else: + name = "auto"+name + try: + return directives.directive(name, None, None)[0] + except AttributeError: + pass try: # docutils 0.4 return directives._directives[name] diff --git a/doc/tools/apigen.py b/doc/tools/apigen.py index dc9a6eb7..5c86db8f 100644 --- a/doc/tools/apigen.py +++ b/doc/tools/apigen.py @@ -194,14 +194,15 @@ class ApiDocWriter(object): classes : list of str A list of (public) class names in the module. """ - exec 'import ' + uri - exec 'mod = ' + uri + mod = __import__(uri, fromlist=[uri]) # find all public objects in the module. obj_strs = [obj for obj in dir(mod) if not obj.startswith('_')] functions = [] classes = [] for obj_str in obj_strs: # find the actual object from its string representation + if obj_str not in mod.__dict__: + continue obj = mod.__dict__[obj_str] # figure out if obj is a function or class if hasattr(obj, 'func_name') or \ From 99029c5287bf6d30afc6996c6cd7379ce57c528e Mon Sep 17 00:00:00 2001 From: Pieter Holtzhausen Date: Fri, 1 Jul 2011 15:07:45 +0200 Subject: [PATCH 02/16] Fixes --- doc/push_github | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/push_github b/doc/push_github index 9b3db2df..77c1c019 100755 --- a/doc/push_github +++ b/doc/push_github @@ -31,9 +31,9 @@ mkdir -p /tmp/_scikits_image_backup for f in $ignore_files; do cp $f /tmp/_scikits_image_backup done -git co scikits/image/version.py +git checkout scikits/image/version.py -git co gh-pages || exit +git checkout gh-pages || exit rm -rf ./* cp -r /tmp/scikits.image.docs/* . From 5b689c7bc2113fc1bc0a35815d1568f88536dcc3 Mon Sep 17 00:00:00 2001 From: Pieter Holtzhausen Date: Mon, 4 Jul 2011 22:03:28 +0200 Subject: [PATCH 03/16] Removed followed files --- doc/source/api/api.txt | 28 ++++++++++++++++++++++++- doc/source/api/scikits.image.filter.txt | 18 ++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/doc/source/api/api.txt b/doc/source/api/api.txt index 3c6beeff..8b073adb 100644 --- a/doc/source/api/api.txt +++ b/doc/source/api/api.txt @@ -6,10 +6,36 @@ API Reference .. toctree:: scikits.image + scikits.image.backend + scikits.image.backend.backend + scikits.image.backend.backend_old scikits.image.color + scikits.image.color.colorconv scikits.image.filter + scikits.image.filter.canny + scikits.image.filter.ctmf + scikits.image.filter.edges + scikits.image.filter.lpi_filter + scikits.image.filter.rank_order scikits.image.graph + scikits.image.graph.heap + scikits.image.graph.heap + scikits.image.graph.mcp + scikits.image.graph.spath scikits.image.io + scikits.image.io._plugins + scikits.image.io.collection + scikits.image.io.io + scikits.image.io.sift scikits.image.morphology - scikits.image.opencv + scikits.image.morphology.ccomp + scikits.image.morphology.ccomp + scikits.image.morphology.cmorph + scikits.image.morphology.cmorph + scikits.image.morphology.grey + scikits.image.morphology.selem + scikits.image.scripts.scivi scikits.image.transform + scikits.image.transform.finite_radon_transform + scikits.image.transform.hough_transform + scikits.image.transform.project diff --git a/doc/source/api/scikits.image.filter.txt b/doc/source/api/scikits.image.filter.txt index 0f1064bd..fdd24b3f 100644 --- a/doc/source/api/scikits.image.filter.txt +++ b/doc/source/api/scikits.image.filter.txt @@ -24,10 +24,18 @@ Inheritance diagram for ``scikits.image.filter``: .. automethod:: __init__ .. autosummary:: + scikits.image.filter.canny scikits.image.filter.inverse scikits.image.filter.median_filter + scikits.image.filter.sobel + scikits.image.filter.test scikits.image.filter.wiener +canny +----- + +.. autofunction:: scikits.image.filter.canny + inverse ------- @@ -38,6 +46,16 @@ median_filter .. autofunction:: scikits.image.filter.median_filter +sobel +----- + +.. autofunction:: scikits.image.filter.sobel + +test +---- + +.. autofunction:: scikits.image.filter.test + wiener ------ From de4a853ecfe6a50067b29d89b5d7421296591eee Mon Sep 17 00:00:00 2001 From: Pieter Holtzhausen Date: Mon, 4 Jul 2011 22:13:18 +0200 Subject: [PATCH 04/16] push script fix --- doc/push_github | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/push_github b/doc/push_github index 77c1c019..e8348c7a 100755 --- a/doc/push_github +++ b/doc/push_github @@ -57,7 +57,7 @@ read git commit -m "Update docs." git push origin gh-pages -git co $branch +git checkout $branch for f in $ignore_files; do cp /tmp/_scikits_image_backup/`basename $f` $f From f3406bc355760122dfd374a03caf87b50b3d6ac7 Mon Sep 17 00:00:00 2001 From: Pieter Holtzhausen Date: Mon, 4 Jul 2011 22:23:12 +0200 Subject: [PATCH 05/16] Push script excludes all git* fix --- doc/push_github | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/push_github b/doc/push_github index e8348c7a..3753263c 100755 --- a/doc/push_github +++ b/doc/push_github @@ -42,7 +42,7 @@ sed -i 's/_static/static/g' `find . -name "*.html"` sed -i 's/_images/images/g' `find . -name "*.html"` mv _static static mv _images images -for f in `find . | grep "./" | grep -v ".git"`; do +for f in `find . | grep "./" | grep -v "\.git"`; do git add $f done From 22c5d7c239f9b363d65430dc0170303314e0bcbc Mon Sep 17 00:00:00 2001 From: Pieter Holtzhausen Date: Tue, 5 Jul 2011 09:13:32 +0200 Subject: [PATCH 06/16] Removed generation --- doc/source/api/api.txt | 41 ---- doc/source/api/scikits.image.analysis.txt | 16 -- doc/source/api/scikits.image.color.txt | 64 ------ doc/source/api/scikits.image.filter.txt | 63 ------ doc/source/api/scikits.image.io.txt | 111 ---------- doc/source/api/scikits.image.opencv.txt | 237 --------------------- doc/source/api/scikits.image.transform.txt | 34 --- 7 files changed, 566 deletions(-) delete mode 100644 doc/source/api/api.txt delete mode 100644 doc/source/api/scikits.image.analysis.txt delete mode 100644 doc/source/api/scikits.image.color.txt delete mode 100644 doc/source/api/scikits.image.filter.txt delete mode 100644 doc/source/api/scikits.image.io.txt delete mode 100644 doc/source/api/scikits.image.opencv.txt delete mode 100644 doc/source/api/scikits.image.transform.txt diff --git a/doc/source/api/api.txt b/doc/source/api/api.txt deleted file mode 100644 index 8b073adb..00000000 --- a/doc/source/api/api.txt +++ /dev/null @@ -1,41 +0,0 @@ -.. AUTO-GENERATED FILE -- DO NOT EDIT! - -API Reference -============= - -.. toctree:: - - scikits.image - scikits.image.backend - scikits.image.backend.backend - scikits.image.backend.backend_old - scikits.image.color - scikits.image.color.colorconv - scikits.image.filter - scikits.image.filter.canny - scikits.image.filter.ctmf - scikits.image.filter.edges - scikits.image.filter.lpi_filter - scikits.image.filter.rank_order - scikits.image.graph - scikits.image.graph.heap - scikits.image.graph.heap - scikits.image.graph.mcp - scikits.image.graph.spath - scikits.image.io - scikits.image.io._plugins - scikits.image.io.collection - scikits.image.io.io - scikits.image.io.sift - scikits.image.morphology - scikits.image.morphology.ccomp - scikits.image.morphology.ccomp - scikits.image.morphology.cmorph - scikits.image.morphology.cmorph - scikits.image.morphology.grey - scikits.image.morphology.selem - scikits.image.scripts.scivi - scikits.image.transform - scikits.image.transform.finite_radon_transform - scikits.image.transform.hough_transform - scikits.image.transform.project diff --git a/doc/source/api/scikits.image.analysis.txt b/doc/source/api/scikits.image.analysis.txt deleted file mode 100644 index 59b6ddd2..00000000 --- a/doc/source/api/scikits.image.analysis.txt +++ /dev/null @@ -1,16 +0,0 @@ -.. AUTO-GENERATED FILE -- DO NOT EDIT! - -Module: :mod:`analysis` -======================= -.. automodule:: scikits.image.analysis - -.. currentmodule:: scikits.image.analysis -.. autosummary:: - - scikits.image.analysis.shortest_path - -shortest_path -------------- - -.. autofunction:: scikits.image.analysis.shortest_path - diff --git a/doc/source/api/scikits.image.color.txt b/doc/source/api/scikits.image.color.txt deleted file mode 100644 index cad07a5d..00000000 --- a/doc/source/api/scikits.image.color.txt +++ /dev/null @@ -1,64 +0,0 @@ -.. AUTO-GENERATED FILE -- DO NOT EDIT! - -Module: :mod:`color` -==================== -.. automodule:: scikits.image.color - -.. currentmodule:: scikits.image.color -.. autosummary:: - - scikits.image.color.convert_colorspace - scikits.image.color.hsv2rgb - scikits.image.color.rgb2gray - scikits.image.color.rgb2grey - scikits.image.color.rgb2hsv - scikits.image.color.rgb2rgbcie - scikits.image.color.rgb2xyz - scikits.image.color.rgbcie2rgb - scikits.image.color.xyz2rgb - -convert_colorspace ------------------- - -.. autofunction:: scikits.image.color.convert_colorspace - -hsv2rgb -------- - -.. autofunction:: scikits.image.color.hsv2rgb - -rgb2gray --------- - -.. autofunction:: scikits.image.color.rgb2gray - -rgb2grey --------- - -.. autofunction:: scikits.image.color.rgb2grey - -rgb2hsv -------- - -.. autofunction:: scikits.image.color.rgb2hsv - -rgb2rgbcie ----------- - -.. autofunction:: scikits.image.color.rgb2rgbcie - -rgb2xyz -------- - -.. autofunction:: scikits.image.color.rgb2xyz - -rgbcie2rgb ----------- - -.. autofunction:: scikits.image.color.rgbcie2rgb - -xyz2rgb -------- - -.. autofunction:: scikits.image.color.xyz2rgb - diff --git a/doc/source/api/scikits.image.filter.txt b/doc/source/api/scikits.image.filter.txt deleted file mode 100644 index fdd24b3f..00000000 --- a/doc/source/api/scikits.image.filter.txt +++ /dev/null @@ -1,63 +0,0 @@ -.. AUTO-GENERATED FILE -- DO NOT EDIT! - -Module: :mod:`filter` -===================== -Inheritance diagram for ``scikits.image.filter``: - -.. inheritance-diagram:: scikits.image.filter - :parts: 3 - -.. automodule:: scikits.image.filter - -.. currentmodule:: scikits.image.filter - -:class:`LPIFilter2D` --------------------- - - -.. autoclass:: LPIFilter2D - :members: - :undoc-members: - :show-inheritance: - :inherited-members: - - .. automethod:: __init__ -.. autosummary:: - - scikits.image.filter.canny - scikits.image.filter.inverse - scikits.image.filter.median_filter - scikits.image.filter.sobel - scikits.image.filter.test - scikits.image.filter.wiener - -canny ------ - -.. autofunction:: scikits.image.filter.canny - -inverse -------- - -.. autofunction:: scikits.image.filter.inverse - -median_filter -------------- - -.. autofunction:: scikits.image.filter.median_filter - -sobel ------ - -.. autofunction:: scikits.image.filter.sobel - -test ----- - -.. autofunction:: scikits.image.filter.test - -wiener ------- - -.. autofunction:: scikits.image.filter.wiener - diff --git a/doc/source/api/scikits.image.io.txt b/doc/source/api/scikits.image.io.txt deleted file mode 100644 index ec8ad675..00000000 --- a/doc/source/api/scikits.image.io.txt +++ /dev/null @@ -1,111 +0,0 @@ -.. AUTO-GENERATED FILE -- DO NOT EDIT! - -Module: :mod:`io` -================= -Inheritance diagram for ``scikits.image.io``: - -.. inheritance-diagram:: scikits.image.io - :parts: 3 - -.. automodule:: scikits.image.io - -.. currentmodule:: scikits.image.io - -:class:`ImageCollection` ------------------------- - - -.. autoclass:: ImageCollection - :members: - :undoc-members: - :show-inheritance: - :inherited-members: - - .. automethod:: __init__ - -:class:`MultiImage` -------------------- - - -.. autoclass:: MultiImage - :members: - :undoc-members: - :show-inheritance: - :inherited-members: - - .. automethod:: __init__ -.. autosummary:: - - scikits.image.io.imread - scikits.image.io.imread_collection - scikits.image.io.imsave - scikits.image.io.imshow - scikits.image.io.load_sift - scikits.image.io.load_surf - scikits.image.io.plugin_info - scikits.image.io.plugins - scikits.image.io.pop - scikits.image.io.push - scikits.image.io.show - scikits.image.io.use_plugin - -imread ------- - -.. autofunction:: scikits.image.io.imread - -imread_collection ------------------ - -.. autofunction:: scikits.image.io.imread_collection - -imsave ------- - -.. autofunction:: scikits.image.io.imsave - -imshow ------- - -.. autofunction:: scikits.image.io.imshow - -load_sift ---------- - -.. autofunction:: scikits.image.io.load_sift - -load_surf ---------- - -.. autofunction:: scikits.image.io.load_surf - -plugin_info ------------ - -.. autofunction:: scikits.image.io.plugin_info - -plugins -------- - -.. autofunction:: scikits.image.io.plugins - -pop ---- - -.. autofunction:: scikits.image.io.pop - -push ----- - -.. autofunction:: scikits.image.io.push - -show ----- - -.. autofunction:: scikits.image.io.show - -use_plugin ----------- - -.. autofunction:: scikits.image.io.use_plugin - diff --git a/doc/source/api/scikits.image.opencv.txt b/doc/source/api/scikits.image.opencv.txt deleted file mode 100644 index 6946677c..00000000 --- a/doc/source/api/scikits.image.opencv.txt +++ /dev/null @@ -1,237 +0,0 @@ -.. AUTO-GENERATED FILE -- DO NOT EDIT! - -Module: :mod:`opencv` -===================== -Inheritance diagram for ``scikits.image.opencv``: - -.. inheritance-diagram:: scikits.image.opencv - :parts: 3 - -.. automodule:: scikits.image.opencv - -.. currentmodule:: scikits.image.opencv - -:class:`cvdoc` --------------- - - -.. autoclass:: cvdoc - :members: - :undoc-members: - :show-inheritance: - :inherited-members: - - .. automethod:: __init__ -.. autosummary:: - - scikits.image.opencv.cvAdaptiveThreshold - scikits.image.opencv.cvCalibrateCamera2 - scikits.image.opencv.cvCanny - scikits.image.opencv.cvCornerEigenValsAndVecs - scikits.image.opencv.cvCornerHarris - scikits.image.opencv.cvCornerMinEigenVal - scikits.image.opencv.cvCvtColor - scikits.image.opencv.cvDilate - scikits.image.opencv.cvDrawChessboardCorners - scikits.image.opencv.cvErode - scikits.image.opencv.cvFilter2D - scikits.image.opencv.cvFindChessboardCorners - scikits.image.opencv.cvFindCornerSubPix - scikits.image.opencv.cvFindExtrinsicCameraParams2 - scikits.image.opencv.cvFindFundamentalMat - scikits.image.opencv.cvFloodFill - scikits.image.opencv.cvGetQuadrangleSubPix - scikits.image.opencv.cvGetRectSubPix - scikits.image.opencv.cvGoodFeaturesToTrack - scikits.image.opencv.cvIntegral - scikits.image.opencv.cvLaplace - scikits.image.opencv.cvLogPolar - scikits.image.opencv.cvMatchTemplate - scikits.image.opencv.cvMorphologyEx - scikits.image.opencv.cvPreCornerDetect - scikits.image.opencv.cvPyrDown - scikits.image.opencv.cvPyrUp - scikits.image.opencv.cvResize - scikits.image.opencv.cvSmooth - scikits.image.opencv.cvSobel - scikits.image.opencv.cvThreshold - scikits.image.opencv.cvUndistort2 - scikits.image.opencv.cvWarpAffine - scikits.image.opencv.cvWarpPerspective - scikits.image.opencv.cvWatershed - -cvAdaptiveThreshold -------------------- - -.. autofunction:: scikits.image.opencv.cvAdaptiveThreshold - -cvCalibrateCamera2 ------------------- - -.. autofunction:: scikits.image.opencv.cvCalibrateCamera2 - -cvCanny -------- - -.. autofunction:: scikits.image.opencv.cvCanny - -cvCornerEigenValsAndVecs ------------------------- - -.. autofunction:: scikits.image.opencv.cvCornerEigenValsAndVecs - -cvCornerHarris --------------- - -.. autofunction:: scikits.image.opencv.cvCornerHarris - -cvCornerMinEigenVal -------------------- - -.. autofunction:: scikits.image.opencv.cvCornerMinEigenVal - -cvCvtColor ----------- - -.. autofunction:: scikits.image.opencv.cvCvtColor - -cvDilate --------- - -.. autofunction:: scikits.image.opencv.cvDilate - -cvDrawChessboardCorners ------------------------ - -.. autofunction:: scikits.image.opencv.cvDrawChessboardCorners - -cvErode -------- - -.. autofunction:: scikits.image.opencv.cvErode - -cvFilter2D ----------- - -.. autofunction:: scikits.image.opencv.cvFilter2D - -cvFindChessboardCorners ------------------------ - -.. autofunction:: scikits.image.opencv.cvFindChessboardCorners - -cvFindCornerSubPix ------------------- - -.. autofunction:: scikits.image.opencv.cvFindCornerSubPix - -cvFindExtrinsicCameraParams2 ----------------------------- - -.. autofunction:: scikits.image.opencv.cvFindExtrinsicCameraParams2 - -cvFindFundamentalMat --------------------- - -.. autofunction:: scikits.image.opencv.cvFindFundamentalMat - -cvFloodFill ------------ - -.. autofunction:: scikits.image.opencv.cvFloodFill - -cvGetQuadrangleSubPix ---------------------- - -.. autofunction:: scikits.image.opencv.cvGetQuadrangleSubPix - -cvGetRectSubPix ---------------- - -.. autofunction:: scikits.image.opencv.cvGetRectSubPix - -cvGoodFeaturesToTrack ---------------------- - -.. autofunction:: scikits.image.opencv.cvGoodFeaturesToTrack - -cvIntegral ----------- - -.. autofunction:: scikits.image.opencv.cvIntegral - -cvLaplace ---------- - -.. autofunction:: scikits.image.opencv.cvLaplace - -cvLogPolar ----------- - -.. autofunction:: scikits.image.opencv.cvLogPolar - -cvMatchTemplate ---------------- - -.. autofunction:: scikits.image.opencv.cvMatchTemplate - -cvMorphologyEx --------------- - -.. autofunction:: scikits.image.opencv.cvMorphologyEx - -cvPreCornerDetect ------------------ - -.. autofunction:: scikits.image.opencv.cvPreCornerDetect - -cvPyrDown ---------- - -.. autofunction:: scikits.image.opencv.cvPyrDown - -cvPyrUp -------- - -.. autofunction:: scikits.image.opencv.cvPyrUp - -cvResize --------- - -.. autofunction:: scikits.image.opencv.cvResize - -cvSmooth --------- - -.. autofunction:: scikits.image.opencv.cvSmooth - -cvSobel -------- - -.. autofunction:: scikits.image.opencv.cvSobel - -cvThreshold ------------ - -.. autofunction:: scikits.image.opencv.cvThreshold - -cvUndistort2 ------------- - -.. autofunction:: scikits.image.opencv.cvUndistort2 - -cvWarpAffine ------------- - -.. autofunction:: scikits.image.opencv.cvWarpAffine - -cvWarpPerspective ------------------ - -.. autofunction:: scikits.image.opencv.cvWarpPerspective - -cvWatershed ------------ - -.. autofunction:: scikits.image.opencv.cvWatershed - diff --git a/doc/source/api/scikits.image.transform.txt b/doc/source/api/scikits.image.transform.txt deleted file mode 100644 index ca1c6792..00000000 --- a/doc/source/api/scikits.image.transform.txt +++ /dev/null @@ -1,34 +0,0 @@ -.. AUTO-GENERATED FILE -- DO NOT EDIT! - -Module: :mod:`transform` -======================== -.. automodule:: scikits.image.transform - -.. currentmodule:: scikits.image.transform -.. autosummary:: - - scikits.image.transform.frt2 - scikits.image.transform.homography - scikits.image.transform.hough - scikits.image.transform.ifrt2 - -frt2 ----- - -.. autofunction:: scikits.image.transform.frt2 - -homography ----------- - -.. autofunction:: scikits.image.transform.homography - -hough ------ - -.. autofunction:: scikits.image.transform.hough - -ifrt2 ------ - -.. autofunction:: scikits.image.transform.ifrt2 - From 93249f215905b50d9eccda59fd50af79f830b694 Mon Sep 17 00:00:00 2001 From: Pieter Holtzhausen Date: Sun, 10 Jul 2011 12:35:16 +0200 Subject: [PATCH 07/16] Script to checkout docs repo and commit (ipython based) --- doc/gh-pages.py | 132 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 doc/gh-pages.py diff --git a/doc/gh-pages.py b/doc/gh-pages.py new file mode 100644 index 00000000..815a466d --- /dev/null +++ b/doc/gh-pages.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python +"""Script to commit the doc build outputs into the github-pages repo. + +Use: + + gh-pages.py [tag] + +If no tag is given, the current output of 'git describe' is used. If given, +that is how the resulting directory will be named. + +In practice, you should use either actual clean tags from a current build or +something like 'current' as a stable URL for the most current version of the """ + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- +import os +import re +import shutil +import sys +from os import chdir as cd +from os.path import join as pjoin + +from subprocess import Popen, PIPE, CalledProcessError, check_call + +#----------------------------------------------------------------------------- +# Globals +#----------------------------------------------------------------------------- + +pages_dir = 'gh-pages' +html_dir = 'build/html' +pdf_dir = 'build/latex' +pages_repo = 'git@github.com:holtzhau/scikits.image-doc.git' + +#----------------------------------------------------------------------------- +# Functions +#----------------------------------------------------------------------------- +def sh(cmd): + """Execute command in a subshell, return status code.""" + return check_call(cmd, shell=True) + + +def sh2(cmd): + """Execute command in a subshell, return stdout. + + Stderr is unbuffered from the subshell.x""" + p = Popen(cmd, stdout=PIPE, shell=True) + out = p.communicate()[0] + retcode = p.returncode + if retcode: + print out.rstrip() + raise CalledProcessError(retcode, cmd) + else: + return out.rstrip() + + +def sh3(cmd): + """Execute command in a subshell, return stdout, stderr + + If anything appears in stderr, print it out to sys.stderr""" + p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True) + out, err = p.communicate() + retcode = p.returncode + if retcode: + raise CalledProcessError(retcode, cmd) + else: + return out.rstrip(), err.rstrip() + + +def init_repo(path): + """clone the gh-pages repo if we haven't already.""" + sh("git clone %s %s"%(pages_repo, path)) + here = os.getcwd() + cd(path) + sh('git checkout gh-pages') + cd(here) + +#----------------------------------------------------------------------------- +# Script starts +#----------------------------------------------------------------------------- +if __name__ == '__main__': + # The tag can be given as a positional argument + try: + tag = sys.argv[1] + except IndexError: + try: + #tag = sh2('git describe ') + tag = sh2('git describe --tags') + except CalledProcessError: + tag = "dev" # Fallback + + startdir = os.getcwd() + if not os.path.exists(pages_dir): + # init the repo + init_repo(pages_dir) + else: + # ensure up-to-date before operating + cd(pages_dir) + sh('git checkout gh-pages') + sh('git pull') + cd(startdir) + + dest = pjoin(pages_dir, tag) + # don't `make html` here, because gh-pages already depends on html in Makefile + # sh('make html') + # This is pretty unforgiving: we unconditionally nuke the destination + # directory, and then copy the html tree in there + shutil.rmtree(dest, ignore_errors=True) + shutil.copytree(html_dir, dest) + #shutil.copy(pjoin(pdf_dir, 'scikits.image.pdf'), pjoin(dest, 'scikits.image.pdf')) + + try: + cd(pages_dir) + status = sh2('git status | head -1') + branch = re.match('\# On branch (.*)$', status).group(1) + if branch != 'gh-pages': + e = 'On %r, git branch is %r, MUST be "gh-pages"' % (pages_dir, + branch) + raise RuntimeError(e) + + sh('git add %s' % tag) + sh2('git commit -m"Updated doc release: %s"' % tag) + + print 'Most recent 3 commits:' + sys.stdout.flush() + sh('git --no-pager log --oneline HEAD~1..') + finally: + cd(startdir) + + print + print 'Now verify the build in: %r' % dest + print "If everything looks good, 'git push'" From fab15a5c71bfb19f1260b32543329f759d707788 Mon Sep 17 00:00:00 2001 From: Pieter Holtzhausen Date: Mon, 11 Jul 2011 14:52:41 +0200 Subject: [PATCH 08/16] Makefile option for gh-pages generation. --- doc/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/Makefile b/doc/Makefile index 55c952df..4da1e8a0 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -108,3 +108,6 @@ doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(DEST)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in build/doctest/output.txt." + +gh-pages: + python gh-pages.py From 964de3d14af6d91670c1c9aae846d88b5bf2490a Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sun, 10 Jul 2011 15:36:14 -0400 Subject: [PATCH 09/16] Use matplotlib's plot_directive.py for Sphinx documentation. Included plot_directive.py is broken for Sphinx 1.0. See http://projects.scipy.org/numpy/ticket/1489 --- doc/source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index bffc63e4..c79e8f82 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -27,7 +27,7 @@ sys.path.append(os.path.join(curpath, '..', 'ext')) # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.pngmath', 'numpydoc', 'sphinx.ext.autosummary', 'sphinx.ext.inheritance_diagram', - 'plot_directive'] + 'matplotlib.sphinxext.plot_directive'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] From f763b6ce3ce2f644c24ab39a56d1040eaa462f73 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sun, 10 Jul 2011 15:47:32 -0400 Subject: [PATCH 10/16] Fix import in apigen.py, which fails when other scikits are present. __import__ can get confused about which scikits path to import when multiple scikits are present on a system. Note that `root_module` is no longer an attribute of `ApiDocWriter` (it wasn't being used anywhere), and it now points to "scikits.image" instead of "scikits". --- doc/tools/apigen.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/doc/tools/apigen.py b/doc/tools/apigen.py index 5c86db8f..58a82fda 100644 --- a/doc/tools/apigen.py +++ b/doc/tools/apigen.py @@ -92,15 +92,21 @@ class ApiDocWriter(object): ''' # 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__[-1] - self.root_path = os.path.join(self.root_path, - os.path.sep.join(package_name.split('.')[1:])) + root_module = self._import(package_name) + self.root_path = root_module.__path__[-1] self.written_modules = None package_name = property(get_package_name, set_package_name, None, 'get/set package_name') + def _import(self, name): + ''' Import namespace package ''' + mod = __import__(name) + components = name.split('.') + for comp in components[1:]: + mod = getattr(mod, comp) + return mod + def _get_object_name(self, line): ''' Get second token in line >>> docwriter = ApiDocWriter('sphinx') From 6f8da31b3b83cda731db5e4c4c4492dfee9c577b Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sun, 10 Jul 2011 15:49:45 -0400 Subject: [PATCH 11/16] Change Makefile so that autogenerated API docs are removed with "make clean". --- doc/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/Makefile b/doc/Makefile index 4da1e8a0..efc61de2 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -30,6 +30,7 @@ help: clean: -rm -rf $(DEST)/* + -rm -rf source/api api: mkdir -p source/api From 12b51ba19980d49b14259d11680950d2ac12b516 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Mon, 11 Jul 2011 09:20:26 -0400 Subject: [PATCH 12/16] Replace plot_directive.py with copy from matplotlib's trunk. --- doc/ext/plot_directive.py | 972 +++++++++++++++++++++++--------------- doc/source/conf.py | 2 +- 2 files changed, 581 insertions(+), 393 deletions(-) diff --git a/doc/ext/plot_directive.py b/doc/ext/plot_directive.py index 05c5ce33..d092f590 100644 --- a/doc/ext/plot_directive.py +++ b/doc/ext/plot_directive.py @@ -1,44 +1,78 @@ """ -A special directive for generating a matplotlib plot. +A directive for including a matplotlib plot in a Sphinx document. -.. warning:: +By default, in HTML output, `plot` will include a .png file with a +link to a high-res .png and .pdf. In LaTeX output, it will include a +.pdf. - This is a hacked version of plot_directive.py from Matplotlib. - It's very much subject to change! +The source code for the plot may be included in one of three ways: + 1. **A path to a source file** as the argument to the directive:: -Usage ------ + .. plot:: path/to/plot.py -Can be used like this:: + When a path to a source file is given, the content of the + directive may optionally contain a caption for the plot:: - .. plot:: examples/example.py + .. plot:: path/to/plot.py - .. plot:: + This is the caption for the plot - import matplotlib.pyplot as plt - plt.plot([1,2,3], [4,5,6]) + Additionally, one my specify the name of a function to call (with + no arguments) immediately after importing the module:: - .. plot:: + .. plot:: path/to/plot.py plot_function1 - A plotting example: + 2. Included as **inline content** to the directive:: - >>> import matplotlib.pyplot as plt - >>> plt.plot([1,2,3], [4,5,6]) + .. plot:: -The content is interpreted as doctest formatted if it has a line starting -with ``>>>``. + import matplotlib.pyplot as plt + import matplotlib.image as mpimg + import numpy as np + img = mpimg.imread('_static/stinkbug.png') + imgplot = plt.imshow(img) -The ``plot`` directive supports the options + 3. Using **doctest** syntax:: + + .. plot:: + A plotting example: + >>> import matplotlib.pyplot as plt + >>> plt.plot([1,2,3], [4,5,6]) + +Options +------- + +The ``plot`` directive supports the following options: format : {'python', 'doctest'} Specify the format of the input include-source : bool - Whether to display the source code. Default can be changed in conf.py - -and the ``image`` directive options ``alt``, ``height``, ``width``, -``scale``, ``align``, ``class``. + Whether to display the source code. The default can be changed + using the `plot_include_source` variable in conf.py + + encoding : str + If this source file is in a non-UTF8 or non-ASCII encoding, + the encoding must be specified using the `:encoding:` option. + The encoding will not be inferred using the ``-*- coding -*-`` + metacomment. + + context : bool + If provided, the code will be run in the context of all + previous plot directives for which the `:context:` option was + specified. This only applies to inline code plot directives, + not those run from files. + + nofigs : bool + If specified, the code block will be run, but no figures will + be inserted. This is usually useful with the ``:context:`` + option. + +Additionally, this directive supports all of the options of the +`image` directive, except for `target` (since plot will add its own +target). These include `alt`, `height`, `width`, `scale`, `align` and +`class`. Configuration options --------------------- @@ -52,9 +86,9 @@ The plot directive has the following configuration options: Code that should be executed before each plot. plot_basedir - Base directory, to which plot:: file names are relative to. - (If None or empty, file names are relative to the directoly where - the file containing the directive is.) + Base directory, to which ``plot::`` file names are relative + to. (If None or empty, file names are relative to the + directoly where the file containing the directive is.) plot_formats File formats to generate. List of tuples or strings:: @@ -64,48 +98,113 @@ The plot directive has the following configuration options: that determine the file format and the DPI. For entries whose DPI was omitted, sensible defaults are chosen. -TODO ----- + plot_html_show_formats + Whether to show links to the files in HTML. -* Refactor Latex output; now it's plain images, but it would be nice - to make them appear side-by-side, or in floats. + plot_rcparams + A dictionary containing any non-standard rcParams that should + be applied before each plot. """ -import sys, os, glob, shutil, imp, warnings, cStringIO, re, textwrap, traceback +import sys, os, glob, shutil, imp, warnings, cStringIO, re, textwrap, \ + traceback, exceptions + +from docutils.parsers.rst import directives +from docutils import nodes +from docutils.parsers.rst.directives.images import Image +align = Image.align import sphinx -import warnings -warnings.warn("A plot_directive module is also available under " - "matplotlib.sphinxext; expect this numpydoc.plot_directive " - "module to be deprecated after relevant features have been " - "integrated there.", - FutureWarning, stacklevel=2) +sphinx_version = sphinx.__version__.split(".") +# The split is necessary for sphinx beta versions where the string is +# '6b1' +sphinx_version = tuple([int(re.split('[a-z]', x)[0]) + for x in sphinx_version[:2]]) +try: + # Sphinx depends on either Jinja or Jinja2 + import jinja2 + def format_template(template, **kw): + return jinja2.Template(template).render(**kw) +except ImportError: + import jinja + def format_template(template, **kw): + return jinja.from_string(template, **kw) + +import matplotlib +import matplotlib.cbook as cbook +matplotlib.use('Agg') +import matplotlib.pyplot as plt +from matplotlib import _pylab_helpers + +__version__ = 2 + +#------------------------------------------------------------------------------ +# Relative pathnames +#------------------------------------------------------------------------------ + +# os.path.relpath is new in Python 2.6 +try: + from os.path import relpath +except ImportError: + # Copied from Python 2.7 + if 'posix' in sys.builtin_module_names: + def relpath(path, start=os.path.curdir): + """Return a relative version of a path""" + from os.path import sep, curdir, join, abspath, commonprefix, \ + pardir + + if not path: + raise ValueError("no path specified") + + start_list = abspath(start).split(sep) + path_list = abspath(path).split(sep) + + # Work out how much of the filepath is shared by start and path. + i = len(commonprefix([start_list, path_list])) + + rel_list = [pardir] * (len(start_list)-i) + path_list[i:] + if not rel_list: + return curdir + return join(*rel_list) + elif 'nt' in sys.builtin_module_names: + def relpath(path, start=os.path.curdir): + """Return a relative version of a path""" + from os.path import sep, curdir, join, abspath, commonprefix, \ + pardir, splitunc + + if not path: + raise ValueError("no path specified") + start_list = abspath(start).split(sep) + path_list = abspath(path).split(sep) + if start_list[0].lower() != path_list[0].lower(): + unc_path, rest = splitunc(path) + unc_start, rest = splitunc(start) + if bool(unc_path) ^ bool(unc_start): + raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)" + % (path, start)) + else: + raise ValueError("path is on drive %s, start on drive %s" + % (path_list[0], start_list[0])) + # Work out how much of the filepath is shared by start and path. + for i in range(min(len(start_list), len(path_list))): + if start_list[i].lower() != path_list[i].lower(): + break + else: + i += 1 + + rel_list = [pardir] * (len(start_list)-i) + path_list[i:] + if not rel_list: + return curdir + return join(*rel_list) + else: + raise RuntimeError("Unsupported platform (no relpath available!)") #------------------------------------------------------------------------------ # Registration hook #------------------------------------------------------------------------------ -def setup(app): - setup.app = app - setup.config = app.config - setup.confdir = app.confdir - - app.add_config_value('plot_pre_code', '', True) - app.add_config_value('plot_include_source', False, True) - app.add_config_value('plot_formats', ['png', 'hires.png', 'pdf'], True) - app.add_config_value('plot_basedir', None, True) - - app.add_directive('plot', plot_directive, True, (0, 1, False), - **plot_directive_options) - -#------------------------------------------------------------------------------ -# plot:: directive -#------------------------------------------------------------------------------ -from docutils.parsers.rst import directives -from docutils import nodes - def plot_directive(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine): return run(arguments, content, options, state_machine, state, lineno) @@ -123,254 +222,74 @@ def _option_boolean(arg): raise ValueError('"%s" unknown boolean' % arg) def _option_format(arg): - return directives.choice(arg, ('python', 'lisp')) + return directives.choice(arg, ('python', 'doctest')) def _option_align(arg): return directives.choice(arg, ("top", "middle", "bottom", "left", "center", "right")) -plot_directive_options = {'alt': directives.unchanged, - 'height': directives.length_or_unitless, - 'width': directives.length_or_percentage_or_unitless, - 'scale': directives.nonnegative_int, - 'align': _option_align, - 'class': directives.class_option, - 'include-source': _option_boolean, - 'format': _option_format, - } +def mark_plot_labels(app, document): + """ + To make plots referenceable, we need to move the reference from + the "htmlonly" (or "latexonly") node to the actual figure node + itself. + """ + for name, explicit in document.nametypes.iteritems(): + if not explicit: + continue + labelid = document.nameids[name] + if labelid is None: + continue + node = document.ids[labelid] + if node.tagname in ('html_only', 'latex_only'): + for n in node: + if n.tagname == 'figure': + sectname = name + for c in n: + if c.tagname == 'caption': + sectname = c.astext() + break + + node['ids'].remove(labelid) + node['names'].remove(name) + n['ids'].append(labelid) + n['names'].append(name) + document.settings.env.labels[name] = \ + document.settings.env.docname, labelid, sectname + break + +def setup(app): + setup.app = app + setup.config = app.config + setup.confdir = app.confdir + + options = {'alt': directives.unchanged, + 'height': directives.length_or_unitless, + 'width': directives.length_or_percentage_or_unitless, + 'scale': directives.nonnegative_int, + 'align': _option_align, + 'class': directives.class_option, + 'include-source': _option_boolean, + 'format': _option_format, + 'context': directives.flag, + 'nofigs': directives.flag, + 'encoding': directives.encoding + } + + app.add_directive('plot', plot_directive, True, (0, 2, False), **options) + app.add_config_value('plot_pre_code', None, True) + app.add_config_value('plot_include_source', False, True) + app.add_config_value('plot_formats', ['png', 'hires.png', 'pdf'], True) + app.add_config_value('plot_basedir', None, True) + app.add_config_value('plot_html_show_formats', True, True) + app.add_config_value('plot_rcparams', {}, True) + + app.connect('doctree-read', mark_plot_labels) #------------------------------------------------------------------------------ -# Generating output +# Doctest handling #------------------------------------------------------------------------------ -from docutils import nodes, utils - -try: - # Sphinx depends on either Jinja or Jinja2 - import jinja2 - def format_template(template, **kw): - return jinja2.Template(template).render(**kw) -except ImportError: - import jinja - def format_template(template, **kw): - return jinja.from_string(template, **kw) - -TEMPLATE = """ -{{ source_code }} - -{{ only_html }} - - {% if source_code %} - (`Source code <{{ source_link }}>`__) - - .. admonition:: Output - :class: plot-output - - {% endif %} - - {% for img in images %} - .. figure:: {{ build_dir }}/{{ img.basename }}.png - {%- for option in options %} - {{ option }} - {% endfor %} - - (`Source code <{{source_link}}>`__) - - {# We do not need to link to all the different image - formats. The .png is included on the webpage, and a the - source snippet is given. - - ( - {%- if not source_code -%} - `Source code <{{source_link}}>`__ - {%- for fmt in img.formats -%} - , `{{ fmt }} <{{ dest_dir }}/{{ img.basename }}.{{ fmt }}>`__ - {%- endfor -%} - {%- else -%} - {%- for fmt in img.formats -%} - {%- if not loop.first -%}, {% endif -%} - `{{ fmt }} <{{ dest_dir }}/{{ img.basename }}.{{ fmt }}>`__ - {%- endfor -%} - {%- endif -%} - ) - - #} - {% endfor %} - -{{ only_latex }} - - {% for img in images %} - .. image:: {{ build_dir }}/{{ img.basename }}.pdf - {% endfor %} - -""" - -class ImageFile(object): - def __init__(self, basename, dirname): - self.basename = basename - self.dirname = dirname - self.formats = [] - - def filename(self, format): - return os.path.join(self.dirname, "%s.%s" % (self.basename, format)) - - def filenames(self): - return [self.filename(fmt) for fmt in self.formats] - -def run(arguments, content, options, state_machine, state, lineno): - if arguments and content: - raise RuntimeError("plot:: directive can't have both args and content") - - document = state_machine.document - config = document.settings.env.config - - options.setdefault('include-source', config.plot_include_source) - - # determine input - rst_file = document.attributes['source'] - rst_dir = os.path.dirname(rst_file) - - if arguments: - if not config.plot_basedir: - source_file_name = os.path.join(rst_dir, - directives.uri(arguments[0])) - else: - source_file_name = os.path.join(setup.confdir, config.plot_basedir, - directives.uri(arguments[0])) - code = open(source_file_name, 'r').read() - output_base = os.path.basename(source_file_name) - else: - source_file_name = rst_file - code = textwrap.dedent("\n".join(map(str, content))) - counter = document.attributes.get('_plot_counter', 0) + 1 - document.attributes['_plot_counter'] = counter - base, ext = os.path.splitext(os.path.basename(source_file_name)) - output_base = '%s-%d.py' % (base, counter) - - base, source_ext = os.path.splitext(output_base) - if source_ext in ('.py', '.rst', '.txt'): - output_base = base - else: - source_ext = '' - - # ensure that LaTeX includegraphics doesn't choke in foo.bar.pdf filenames - output_base = output_base.replace('.', '-') - - # is it in doctest format? - is_doctest = contains_doctest(code) - if options.has_key('format'): - if options['format'] == 'python': - is_doctest = False - else: - is_doctest = True - - # determine output directory name fragment - source_rel_name = relpath(source_file_name, setup.confdir) - source_rel_dir = os.path.dirname(source_rel_name) - while source_rel_dir.startswith(os.path.sep): - source_rel_dir = source_rel_dir[1:] - - # build_dir: where to place output files (temporarily) - build_dir = os.path.join(os.path.dirname(setup.app.doctreedir), - 'plot_directive', - source_rel_dir) - if not os.path.exists(build_dir): - os.makedirs(build_dir) - - # output_dir: final location in the builder's directory - dest_dir = os.path.abspath(os.path.join(setup.app.builder.outdir, - source_rel_dir)) - - # how to link to files from the RST file - dest_dir_link = os.path.join(relpath(setup.confdir, rst_dir), - source_rel_dir).replace(os.path.sep, '/') - build_dir_link = relpath(build_dir, rst_dir).replace(os.path.sep, '/') - source_link = dest_dir_link + '/' + output_base + source_ext - - # make figures - try: - images = makefig(code, source_file_name, build_dir, output_base, - config) - except PlotError, err: - reporter = state.memo.reporter - sm = reporter.system_message( - 3, "Exception occurred in plotting %s: %s" % (output_base, err), - line=lineno) - return [sm] - - # generate output restructuredtext - if options['include-source']: - if is_doctest: - lines = [''] - lines += [row.rstrip() for row in code.split('\n')] - else: - lines = ['.. code-block:: python', ''] - lines += [' %s' % row.rstrip() for row in code.split('\n')] - source_code = "\n".join(lines) - else: - source_code = "" - - opts = [':%s: %s' % (key, val) for key, val in options.items() - if key in ('alt', 'height', 'width', 'scale', 'align', 'class')] - - if sphinx.__version__ >= "0.6": - only_html = ".. only:: html" - only_latex = ".. only:: latex" - else: - only_html = ".. htmlonly::" - only_latex = ".. latexonly::" - - result = format_template( - TEMPLATE, - dest_dir=dest_dir_link, - build_dir=build_dir_link, - source_link=source_link, - only_html=only_html, - only_latex=only_latex, - options=opts, - images=images, - source_code=source_code) - - lines = result.split("\n") - if len(lines): - state_machine.insert_input( - lines, state_machine.input_lines.source(0)) - - # copy image files to builder's output directory - if not os.path.exists(dest_dir): - os.makedirs(dest_dir) - -# Commented out so that images are not copied to the 'plots' -# directory. Sphinx copies to images to '_images' anyway, so no need. - -# for img in images: -# for fn in img.filenames(): -# shutil.copyfile(fn, os.path.join(dest_dir, os.path.basename(fn))) - - # copy script (if necessary) - if source_file_name == rst_file: - target_name = os.path.join(dest_dir, output_base + source_ext) - f = open(target_name, 'w') - f.write(unescape_doctest(code)) - f.close() - else: - shutil.copy(source_file_name, dest_dir) - - return [] - - -#------------------------------------------------------------------------------ -# Run code and capture figures -#------------------------------------------------------------------------------ - -import matplotlib -matplotlib.use('Agg') -import matplotlib.pyplot as plt -import matplotlib.image as image -from matplotlib import _pylab_helpers - -import exceptions - def contains_doctest(text): try: # check if it's valid Python as-is @@ -402,12 +321,127 @@ def unescape_doctest(text): code += "\n" return code +def split_code_at_show(text): + """ + Split code at plt.show() + + """ + + parts = [] + is_doctest = contains_doctest(text) + + part = [] + for line in text.split("\n"): + if (not is_doctest and line.strip() == 'plt.show()') or \ + (is_doctest and line.strip() == '>>> plt.show()'): + part.append(line) + parts.append("\n".join(part)) + part = [] + else: + part.append(line) + if "\n".join(part).strip(): + parts.append("\n".join(part)) + return parts + +#------------------------------------------------------------------------------ +# Template +#------------------------------------------------------------------------------ + + +TEMPLATE = """ +{{ source_code }} + +{{ only_html }} + + {% if source_link or (html_show_formats and not multi_image) %} + ( + {%- if source_link -%} + `Source code <{{ source_link }}>`__ + {%- endif -%} + {%- if html_show_formats and not multi_image -%} + {%- for img in images -%} + {%- for fmt in img.formats -%} + {%- if source_link or not loop.first -%}, {% endif -%} + `{{ fmt }} <{{ dest_dir }}/{{ img.basename }}.{{ fmt }}>`__ + {%- endfor -%} + {%- endfor -%} + {%- endif -%} + ) + {% endif %} + + {% for img in images %} + .. figure:: {{ build_dir }}/{{ img.basename }}.png + {%- for option in options %} + {{ option }} + {% endfor %} + + {% if html_show_formats and multi_image -%} + ( + {%- for fmt in img.formats -%} + {%- if not loop.first -%}, {% endif -%} + `{{ fmt }} <{{ dest_dir }}/{{ img.basename }}.{{ fmt }}>`__ + {%- endfor -%} + ) + {%- endif -%} + + {{ caption }} + {% endfor %} + +{{ only_latex }} + + {% for img in images %} + .. image:: {{ build_dir }}/{{ img.basename }}.pdf + {% endfor %} + +""" + +exception_template = """ +.. htmlonly:: + + [`source code <%(linkdir)s/%(basename)s.py>`__] + +Exception occurred rendering plot. + +""" + +# the context of the plot for all directives specified with the +# :context: option +plot_context = dict() + +class ImageFile(object): + def __init__(self, basename, dirname): + self.basename = basename + self.dirname = dirname + self.formats = [] + + def filename(self, format): + return os.path.join(self.dirname, "%s.%s" % (self.basename, format)) + + def filenames(self): + return [self.filename(fmt) for fmt in self.formats] + +def out_of_date(original, derived): + """ + Returns True if derivative is out-of-date wrt original, + both of which are full file paths. + """ + return (not os.path.exists(derived) or + (os.path.exists(original) and + os.stat(derived).st_mtime < os.stat(original).st_mtime)) + class PlotError(RuntimeError): pass -def run_code(code, code_path): +def run_code(code, code_path, ns=None, function_name=None): + """ + Import a Python module from a path, and run the function given by + name, if function_name is not None. + """ + # Change the working directory to the directory of the example, so - # it can get at its data files, if any. + # it can get at its data files, if any. Add its path to sys.path + # so it can import any helper modules sitting beside it. + pwd = os.getcwd() old_sys_path = list(sys.path) if code_path is not None: @@ -422,13 +456,20 @@ def run_code(code, code_path): # Reset sys.argv old_sys_argv = sys.argv sys.argv = [code_path] - + try: try: code = unescape_doctest(code) - ns = {} - exec setup.config.plot_pre_code in ns + if ns is None: + ns = {} + if not ns: + if setup.config.plot_pre_code is None: + exec "import numpy as np\nfrom matplotlib import pyplot as plt\n" in ns + else: + exec setup.config.plot_pre_code in ns exec code in ns + if function_name is not None: + exec function_name + "()" in ns except (Exception, SystemExit), err: raise PlotError(traceback.format_exc()) finally: @@ -438,29 +479,22 @@ def run_code(code, code_path): sys.stdout = stdout return ns +def clear_state(plot_rcparams): + plt.close('all') + matplotlib.rc_file_defaults() + matplotlib.rcParams.update(plot_rcparams) -#------------------------------------------------------------------------------ -# Generating figures -#------------------------------------------------------------------------------ - -def out_of_date(original, derived): +def render_figures(code, code_path, output_dir, output_base, context, + function_name, config): """ - Returns True if derivative is out-of-date wrt original, - both of which are full file paths. + Run a pyplot script and save the low and high res PNGs and a PDF + in outdir. + + Save the images under *output_dir* with file names derived from + *output_base* """ - return (not os.path.exists(derived) - or os.stat(derived).st_mtime < os.stat(original).st_mtime) - - -def makefig(code, code_path, output_dir, output_base, config): - """ - Run a pyplot script *code* and save the images under *output_dir* - with file names derived from *output_base* - - """ - # -- Parse format list - default_dpi = {'png': 80, 'hires.png': 200, 'pdf': 50} + default_dpi = {'png': 80, 'hires.png': 200, 'pdf': 200} formats = [] for fmt in config.plot_formats: if isinstance(fmt, str): @@ -472,6 +506,9 @@ def makefig(code, code_path, output_dir, output_base, config): # -- Try to determine if all images already exist + code_pieces = split_code_at_show(code) + + # Look for single-figure output files first # Look for single-figure output files first all_exists = True img = ImageFile(output_base, output_dir) @@ -482,95 +519,246 @@ def makefig(code, code_path, output_dir, output_base, config): img.formats.append(format) if all_exists: - return [img] + return [(code, [img])] # Then look for multi-figure output files - images = [] + results = [] all_exists = True - for i in xrange(1000): - img = ImageFile('%s_%02d' % (output_base, i), output_dir) - for format, dpi in formats: - if out_of_date(code_path, img.filename(format)): - all_exists = False + for i, code_piece in enumerate(code_pieces): + images = [] + for j in xrange(1000): + if len(code_pieces) > 1: + img = ImageFile('%s_%02d_%02d' % (output_base, i, j), output_dir) + else: + img = ImageFile('%s_%02d' % (output_base, j), output_dir) + for format, dpi in formats: + if out_of_date(code_path, img.filename(format)): + all_exists = False + break + img.formats.append(format) + + # assume that if we have one, we have them all + if not all_exists: + all_exists = (j > 0) break - img.formats.append(format) - - # assume that if we have one, we have them all + images.append(img) if not all_exists: - all_exists = (i > 0) break - images.append(img) + results.append((code_piece, images)) if all_exists: - return images + return results - # -- We didn't find the files, so build them + # We didn't find the files, so build them - # Clear between runs - plt.close('all') + results = [] + if context: + ns = plot_context + else: + ns = {} - # Run code - run_code(code, code_path) + for i, code_piece in enumerate(code_pieces): + if not context: + clear_state(config.plot_rcparams) + run_code(code_piece, code_path, ns, function_name) - # Collect images - images = [] + images = [] + fig_managers = _pylab_helpers.Gcf.get_all_fig_managers() + for j, figman in enumerate(fig_managers): + if len(fig_managers) == 1 and len(code_pieces) == 1: + img = ImageFile(output_base, output_dir) + elif len(code_pieces) == 1: + img = ImageFile("%s_%02d" % (output_base, j), output_dir) + else: + img = ImageFile("%s_%02d_%02d" % (output_base, i, j), + output_dir) + images.append(img) + for format, dpi in formats: + try: + figman.canvas.figure.savefig(img.filename(format), dpi=dpi) + except exceptions.BaseException as err: + raise PlotError(traceback.format_exc()) + img.formats.append(format) - fig_managers = _pylab_helpers.Gcf.get_all_fig_managers() - for i, figman in enumerate(fig_managers): - if len(fig_managers) == 1: - img = ImageFile(output_base, output_dir) + results.append((code_piece, images)) + + return results + +def run(arguments, content, options, state_machine, state, lineno): + # The user may provide a filename *or* Python code content, but not both + if arguments and content: + raise RuntimeError("plot:: directive can't have both args and content") + + document = state_machine.document + config = document.settings.env.config + nofigs = options.has_key('nofigs') + + options.setdefault('include-source', config.plot_include_source) + context = options.has_key('context') + + rst_file = document.attributes['source'] + rst_dir = os.path.dirname(rst_file) + + if len(arguments): + if not config.plot_basedir: + source_file_name = os.path.join(setup.app.builder.srcdir, + directives.uri(arguments[0])) else: - img = ImageFile("%s_%02d" % (output_base, i), output_dir) - images.append(img) - for format, dpi in formats: - try: - figman.canvas.figure.savefig(img.filename(format), dpi=dpi) - except exceptions.BaseException, err: - raise PlotError(traceback.format_exc()) - img.formats.append(format) + source_file_name = os.path.join(setup.confdir, config.plot_basedir, + directives.uri(arguments[0])) - return images + # If there is content, it will be passed as a caption. + caption = '\n'.join(content) - -#------------------------------------------------------------------------------ -# Relative pathnames -#------------------------------------------------------------------------------ - -try: - from os.path import relpath -except ImportError: - def relpath(target, base=os.curdir): - """ - Return a relative path to the target from either the current - dir or an optional base dir. Base can be a directory - specified either as absolute or relative to current dir. - """ - - if not os.path.exists(target): - raise OSError, 'Target does not exist: '+target - - if not os.path.isdir(base): - raise OSError, 'Base is not a directory or does not exist: '+base - - base_list = (os.path.abspath(base)).split(os.sep) - target_list = (os.path.abspath(target)).split(os.sep) - - # On the windows platform the target may be on a completely - # different drive from the base. - if os.name in ['nt','dos','os2'] and base_list[0] <> target_list[0]: - raise OSError, 'Target is on a different drive to base. Target: '+target_list[0].upper()+', base: '+base_list[0].upper() - - # Starting from the filepath root, work out how much of the - # filepath is shared by base and target. - for i in range(min(len(base_list), len(target_list))): - if base_list[i] <> target_list[i]: break + # If the optional function name is provided, use it + if len(arguments) == 2: + function_name = arguments[1] else: - # If we broke out of the loop, i is pointing to the first - # differing path elements. If we didn't break out of the - # loop, i is pointing to identical path elements. - # Increment i so that in all cases it points to the first - # differing path elements. - i+=1 + function_name = None - rel_list = [os.pardir] * (len(base_list)-i) + target_list[i:] - return os.path.join(*rel_list) + fd = open(source_file_name, 'r') + code = fd.read() + fd.close() + output_base = os.path.basename(source_file_name) + else: + source_file_name = rst_file + code = textwrap.dedent("\n".join(map(str, content))) + counter = document.attributes.get('_plot_counter', 0) + 1 + document.attributes['_plot_counter'] = counter + base, ext = os.path.splitext(os.path.basename(source_file_name)) + output_base = '%s-%d.py' % (base, counter) + function_name = None + caption = '' + + base, source_ext = os.path.splitext(output_base) + if source_ext in ('.py', '.rst', '.txt'): + output_base = base + else: + source_ext = '' + + # ensure that LaTeX includegraphics doesn't choke in foo.bar.pdf filenames + output_base = output_base.replace('.', '-') + + # is it in doctest format? + is_doctest = contains_doctest(code) + if options.has_key('format'): + if options['format'] == 'python': + is_doctest = False + else: + is_doctest = True + + # determine output directory name fragment + source_rel_name = relpath(source_file_name, setup.confdir) + source_rel_dir = os.path.dirname(source_rel_name) + while source_rel_dir.startswith(os.path.sep): + source_rel_dir = source_rel_dir[1:] + + # build_dir: where to place output files (temporarily) + build_dir = os.path.join(os.path.dirname(setup.app.doctreedir), + 'plot_directive', + source_rel_dir) + # get rid of .. in paths, also changes pathsep + # see note in Python docs for warning about symbolic links on Windows. + # need to compare source and dest paths at end + build_dir = os.path.normpath(build_dir) + + if not os.path.exists(build_dir): + os.makedirs(build_dir) + + # output_dir: final location in the builder's directory + dest_dir = os.path.abspath(os.path.join(setup.app.builder.outdir, + source_rel_dir)) + if not os.path.exists(dest_dir): + os.makedirs(dest_dir) # no problem here for me, but just use built-ins + + # how to link to files from the RST file + dest_dir_link = os.path.join(relpath(setup.confdir, rst_dir), + source_rel_dir).replace(os.path.sep, '/') + build_dir_link = relpath(build_dir, rst_dir).replace(os.path.sep, '/') + source_link = dest_dir_link + '/' + output_base + source_ext + + # make figures + try: + results = render_figures(code, source_file_name, build_dir, output_base, + context, function_name, config) + errors = [] + except PlotError, err: + reporter = state.memo.reporter + sm = reporter.system_message( + 2, "Exception occurred in plotting %s: %s" % (output_base, err), + line=lineno) + results = [(code, [])] + errors = [sm] + + # Properly indent the caption + caption = '\n'.join(' ' + line.strip() + for line in caption.split('\n')) + + # generate output restructuredtext + total_lines = [] + for j, (code_piece, images) in enumerate(results): + if options['include-source']: + if is_doctest: + lines = [''] + lines += [row.rstrip() for row in code_piece.split('\n')] + else: + lines = ['.. code-block:: python', ''] + lines += [' %s' % row.rstrip() + for row in code_piece.split('\n')] + source_code = "\n".join(lines) + else: + source_code = "" + + if nofigs: + images = [] + + opts = [':%s: %s' % (key, val) for key, val in options.items() + if key in ('alt', 'height', 'width', 'scale', 'align', 'class')] + + only_html = ".. only:: html" + only_latex = ".. only:: latex" + + if j == 0: + src_link = source_link + else: + src_link = None + + result = format_template( + TEMPLATE, + dest_dir=dest_dir_link, + build_dir=build_dir_link, + source_link=src_link, + multi_image=len(images) > 1, + only_html=only_html, + only_latex=only_latex, + options=opts, + images=images, + source_code=source_code, + html_show_formats=config.plot_html_show_formats, + caption=caption) + + total_lines.extend(result.split("\n")) + total_lines.extend("\n") + + if total_lines: + state_machine.insert_input(total_lines, source=source_file_name) + + # copy image files to builder's output directory, if necessary + if not os.path.exists(dest_dir): + cbook.mkdirs(dest_dir) + + for code_piece, images in results: + for img in images: + for fn in img.filenames(): + destimg = os.path.join(dest_dir, os.path.basename(fn)) + if fn != destimg: + shutil.copyfile(fn, destimg) + + # copy script (if necessary) + if source_file_name == rst_file: + target_name = os.path.join(dest_dir, output_base + source_ext) + f = open(target_name, 'w') + f.write(unescape_doctest(code)) + f.close() + + return errors diff --git a/doc/source/conf.py b/doc/source/conf.py index c79e8f82..bffc63e4 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -27,7 +27,7 @@ sys.path.append(os.path.join(curpath, '..', 'ext')) # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.pngmath', 'numpydoc', 'sphinx.ext.autosummary', 'sphinx.ext.inheritance_diagram', - 'matplotlib.sphinxext.plot_directive'] + 'plot_directive'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] From aef8d50f5bc9f5bef379fb633ba2c0ece7422007 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Mon, 11 Jul 2011 09:24:32 -0400 Subject: [PATCH 13/16] Fix lengths of restructuredtext section headers in docs. --- doc/source/gitwash/forking_hell.txt | 6 +++--- doc/source/gitwash/index.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/source/gitwash/forking_hell.txt b/doc/source/gitwash/forking_hell.txt index c367ce07..8ef86ffc 100644 --- a/doc/source/gitwash/forking_hell.txt +++ b/doc/source/gitwash/forking_hell.txt @@ -1,8 +1,8 @@ .. _forking: -========================================== +============================================ Making your own copy (fork) of scikits.image -========================================== +============================================ You need to do this only once. The instructions here are very similar to the instructions at http://help.github.com/forking/ - please see that @@ -18,7 +18,7 @@ You then need to configure your account to allow write access - see the ``Generating SSH keys`` help on `github help`_. Create your own forked copy of scikits.image_ -========================================= +============================================= #. Log into your github_ account. #. Go to the scikits.image_ github home at `scikits.image github`_. diff --git a/doc/source/gitwash/index.txt b/doc/source/gitwash/index.txt index c67e629f..0acb8fb9 100644 --- a/doc/source/gitwash/index.txt +++ b/doc/source/gitwash/index.txt @@ -1,7 +1,7 @@ .. _using-git: Working with *scikits.image* source code -====================================== +======================================== Contents: From 676b91180285937e16ab31e91aa94039fad0f67a Mon Sep 17 00:00:00 2001 From: Pieter Holtzhausen Date: Fri, 15 Jul 2011 11:43:43 +0200 Subject: [PATCH 14/16] Update the numpy sphinx extensions from http://projects.scipy.org/numpy/browser/trunk/doc/sphinxext/ --- doc/ext/docscrape.py | 61 ++++++++-------- doc/ext/docscrape_sphinx.py | 25 ++++--- doc/ext/numpydoc.py | 141 ++++++++++++++---------------------- 3 files changed, 100 insertions(+), 127 deletions(-) diff --git a/doc/ext/docscrape.py b/doc/ext/docscrape.py index 0e073da9..ad5998cc 100644 --- a/doc/ext/docscrape.py +++ b/doc/ext/docscrape.py @@ -84,7 +84,7 @@ class Reader(object): class NumpyDocString(object): - def __init__(self,docstring): + def __init__(self, docstring, config={}): docstring = textwrap.dedent(docstring).split('\n') self._doc = Reader(docstring) @@ -183,7 +183,7 @@ class NumpyDocString(object): return params - + _name_rgx = re.compile(r"^\s*(:(?P\w+):`(?P[a-zA-Z0-9_.-]+)`|" r" (?P[a-zA-Z0-9_.-]+))\s*", re.X) def _parse_see_also(self, content): @@ -216,7 +216,7 @@ class NumpyDocString(object): current_func = None rest = [] - + for line in content: if not line.strip(): continue @@ -258,7 +258,7 @@ class NumpyDocString(object): if len(line) > 2: out[line[1]] = strip_each_in(line[2].split(',')) return out - + def _parse_summary(self): """Grab signature (if given) and summary""" if self._is_at_section(): @@ -275,7 +275,7 @@ class NumpyDocString(object): if not self._is_at_section(): self['Extended Summary'] = self._read_to_next_section() - + def _parse(self): self._doc.reset() self._parse_summary() @@ -408,22 +408,17 @@ def header(text, style='-'): class FunctionDoc(NumpyDocString): - def __init__(self, func, role='func', doc=None): + def __init__(self, func, role='func', doc=None, config={}): self._f = func self._role = role # e.g. "func" or "meth" - if doc is None: - doc = inspect.getdoc(func) or '' - try: - NumpyDocString.__init__(self, doc) - except ValueError, e: - print '*'*78 - print "ERROR: '%s' while parsing `%s`" % (e, self._f) - print '*'*78 - #print "Docstring follows:" - #print doclines - #print '='*78 - if not self['Signature']: + if doc is None: + if func is None: + raise ValueError("No function or docstring given") + doc = inspect.getdoc(func) or '' + NumpyDocString.__init__(self, doc) + + if not self['Signature'] and func is not None: func, func_name = self.get_func() try: # try to read signature @@ -442,7 +437,7 @@ class FunctionDoc(NumpyDocString): else: func = self._f return func, func_name - + def __str__(self): out = '' @@ -463,35 +458,41 @@ class FunctionDoc(NumpyDocString): class ClassDoc(NumpyDocString): - def __init__(self,cls,modulename='',func_doc=FunctionDoc,doc=None): - if not inspect.isclass(cls): - raise ValueError("Initialise using a class. Got %r" % cls) + def __init__(self, cls, doc=None, modulename='', func_doc=FunctionDoc, + config={}): + if not inspect.isclass(cls) and cls is not None: + raise ValueError("Expected a class or None, but got %r" % cls) self._cls = cls if modulename and not modulename.endswith('.'): modulename += '.' self._mod = modulename - self._name = cls.__name__ - self._func_doc = func_doc if doc is None: + if cls is None: + raise ValueError("No class or documentation string given") doc = pydoc.getdoc(cls) NumpyDocString.__init__(self, doc) - if not self['Methods']: - self['Methods'] = [(name, '', '') for name in sorted(self.methods)] - - if not self['Attributes']: - self['Attributes'] = [(name, '', '') - for name in sorted(self.properties)] + if config.get('show_class_members', True): + if not self['Methods']: + self['Methods'] = [(name, '', '') + for name in sorted(self.methods)] + if not self['Attributes']: + self['Attributes'] = [(name, '', '') + for name in sorted(self.properties)] @property def methods(self): + if self._cls is None: + return [] return [name for name,func in inspect.getmembers(self._cls) if not name.startswith('_') and callable(func)] @property def properties(self): + if self._cls is None: + return [] return [name for name,func in inspect.getmembers(self._cls) if not name.startswith('_') and func is None] diff --git a/doc/ext/docscrape_sphinx.py b/doc/ext/docscrape_sphinx.py index 12907731..9f4350d4 100644 --- a/doc/ext/docscrape_sphinx.py +++ b/doc/ext/docscrape_sphinx.py @@ -3,7 +3,9 @@ import sphinx from docscrape import NumpyDocString, FunctionDoc, ClassDoc class SphinxDocString(NumpyDocString): - use_plots = False + def __init__(self, docstring, config={}): + self.use_plots = config.get('use_plots', False) + NumpyDocString.__init__(self, docstring, config=config) # string conversion routines def _str_header(self, name, symbol='`'): @@ -189,17 +191,21 @@ class SphinxDocString(NumpyDocString): return '\n'.join(out) class SphinxFunctionDoc(SphinxDocString, FunctionDoc): - pass + def __init__(self, obj, doc=None, config={}): + self.use_plots = config.get('use_plots', False) + FunctionDoc.__init__(self, obj, doc=doc, config=config) class SphinxClassDoc(SphinxDocString, ClassDoc): - pass + def __init__(self, obj, doc=None, func_doc=None, config={}): + self.use_plots = config.get('use_plots', False) + ClassDoc.__init__(self, obj, doc=doc, func_doc=None, config=config) class SphinxObjDoc(SphinxDocString): - def __init__(self, obj, doc): + def __init__(self, obj, doc=None, config={}): self._f = obj - SphinxDocString.__init__(self, doc) + SphinxDocString.__init__(self, doc, config=config) -def get_doc_object(obj, what=None, doc=None): +def get_doc_object(obj, what=None, doc=None, config={}): if what is None: if inspect.isclass(obj): what = 'class' @@ -210,10 +216,11 @@ def get_doc_object(obj, what=None, doc=None): else: what = 'object' if what == 'class': - return SphinxClassDoc(obj, '', func_doc=SphinxFunctionDoc, doc=doc) + return SphinxClassDoc(obj, func_doc=SphinxFunctionDoc, doc=doc, + config=config) elif what in ('function', 'method'): - return SphinxFunctionDoc(obj, '', doc=doc) + return SphinxFunctionDoc(obj, doc=doc, config=config) else: if doc is None: doc = pydoc.getdoc(obj) - return SphinxObjDoc(obj, doc) + return SphinxObjDoc(obj, doc, config=config) diff --git a/doc/ext/numpydoc.py b/doc/ext/numpydoc.py index 6667c429..aa390056 100644 --- a/doc/ext/numpydoc.py +++ b/doc/ext/numpydoc.py @@ -24,14 +24,16 @@ import inspect def mangle_docstrings(app, what, name, obj, options, lines, reference_offset=[0]): + cfg = dict(use_plots=app.config.numpydoc_use_plots, + show_class_members=app.config.numpydoc_show_class_members) + if what == 'module': # Strip top title title_re = re.compile(ur'^\s*[#*=]{4,}\n[a-z0-9 -]+\n[#*=]{4,}\s*', re.I|re.S) lines[:] = title_re.sub(u'', u"\n".join(lines)).split(u"\n") else: - doc = get_doc_object(obj, what, u"\n".join(lines)) - doc.use_plots = app.config.numpydoc_use_plots + doc = get_doc_object(obj, what, u"\n".join(lines), config=cfg) lines[:] = unicode(doc).split(u"\n") if app.config.numpydoc_edit_link and hasattr(obj, '__name__') and \ @@ -71,7 +73,8 @@ def mangle_docstrings(app, what, name, obj, options, lines, def mangle_signature(app, what, name, obj, options, sig, retann): # Do not try to inspect classes that don't define `__init__` if (inspect.isclass(obj) and - 'initializes x; see ' in pydoc.getdoc(obj.__init__)): + (not hasattr(obj, '__init__') or + 'initializes x; see ' in pydoc.getdoc(obj.__init__))): return '', '' if not (callable(obj) or hasattr(obj, '__argspec_is_invalid_')): return @@ -82,80 +85,63 @@ def mangle_signature(app, what, name, obj, options, sig, retann): sig = re.sub(u"^[^(]*", u"", doc['Signature']) return sig, u'' -def initialize(app): - try: - app.connect('autodoc-process-signature', mangle_signature) - except: - monkeypatch_sphinx_ext_autodoc() - def setup(app, get_doc_object_=get_doc_object): global get_doc_object get_doc_object = get_doc_object_ - - app.connect('autodoc-process-docstring', mangle_docstrings) - app.connect('builder-inited', initialize) - app.add_config_value('numpydoc_edit_link', None, True) - app.add_config_value('numpydoc_use_plots', None, False) - # Extra mangling directives - name_type = { - 'cfunction': 'function', - 'cmember': 'attribute', - 'cmacro': 'function', - 'ctype': 'class', - 'cvar': 'object', - 'class': 'class', + app.connect('autodoc-process-docstring', mangle_docstrings) + app.connect('autodoc-process-signature', mangle_signature) + app.add_config_value('numpydoc_edit_link', None, False) + app.add_config_value('numpydoc_use_plots', None, False) + app.add_config_value('numpydoc_show_class_members', True, True) + + # Extra mangling domains + app.add_domain(NumpyPythonDomain) + app.add_domain(NumpyCDomain) + +#------------------------------------------------------------------------------ +# Docstring-mangling domains +#------------------------------------------------------------------------------ + +from docutils.statemachine import ViewList +from sphinx.domains.c import CDomain +from sphinx.domains.python import PythonDomain + +class ManglingDomainBase(object): + directive_mangling_map = {} + + def __init__(self, *a, **kw): + super(ManglingDomainBase, self).__init__(*a, **kw) + self.wrap_mangling_directives() + + def wrap_mangling_directives(self): + for name, objtype in self.directive_mangling_map.items(): + self.directives[name] = wrap_mangling_directive( + self.directives[name], objtype) + +class NumpyPythonDomain(ManglingDomainBase, PythonDomain): + name = 'np' + directive_mangling_map = { 'function': 'function', - 'attribute': 'attribute', + 'class': 'class', + 'exception': 'class', 'method': 'function', - 'staticmethod': 'function', 'classmethod': 'function', + 'staticmethod': 'function', + 'attribute': 'attribute', } - for name, objtype in name_type.items(): - app.add_directive('np-' + name, wrap_mangling_directive(name, objtype)) - -#------------------------------------------------------------------------------ -# Input-mangling directives -#------------------------------------------------------------------------------ -from docutils.statemachine import ViewList - -def get_directive(name): - from docutils.parsers.rst import directives - try: - return directives.directive(name, None, None)[0] - except AttributeError: - if "method" in name: - name = "automethod" - else: - name = "auto"+name - try: - return directives.directive(name, None, None)[0] - except AttributeError: - pass - try: - # docutils 0.4 - return directives._directives[name] - except (AttributeError, KeyError): - raise RuntimeError("No directive named '%s' found" % name) - -def wrap_mangling_directive(base_directive_name, objtype): - base_directive = get_directive(base_directive_name) - - if inspect.isfunction(base_directive): - base_func = base_directive - class base_directive(Directive): - required_arguments = base_func.arguments[0] - optional_arguments = base_func.arguments[1] - final_argument_whitespace = base_func.arguments[2] - option_spec = base_func.options - has_content = base_func.content - def run(self): - return base_func(self.name, self.arguments, self.options, - self.content, self.lineno, - self.content_offset, self.block_text, - self.state, self.state_machine) +class NumpyCDomain(ManglingDomainBase, CDomain): + name = 'np-c' + directive_mangling_map = { + 'function': 'function', + 'member': 'attribute', + 'macro': 'function', + 'type': 'class', + 'var': 'object', + } +def wrap_mangling_directive(base_directive, objtype): class directive(base_directive): def run(self): env = self.state.document.settings.env @@ -176,24 +162,3 @@ def wrap_mangling_directive(base_directive_name, objtype): return directive -#------------------------------------------------------------------------------ -# Monkeypatch sphinx.ext.autodoc to accept argspecless autodocs (Sphinx < 0.5) -#------------------------------------------------------------------------------ - -def monkeypatch_sphinx_ext_autodoc(): - global _original_format_signature - import sphinx.ext.autodoc - - if sphinx.ext.autodoc.format_signature is our_format_signature: - return - - print "[numpydoc] Monkeypatching sphinx.ext.autodoc ..." - _original_format_signature = sphinx.ext.autodoc.format_signature - sphinx.ext.autodoc.format_signature = our_format_signature - -def our_format_signature(what, obj): - r = mangle_signature(None, what, None, obj, None, None, None) - if r is not None: - return r[0] - else: - return _original_format_signature(what, obj) From aa32054b1191264b3df030cb504c78a45007389d Mon Sep 17 00:00:00 2001 From: Pieter Holtzhausen Date: Fri, 15 Jul 2011 17:30:55 +0200 Subject: [PATCH 15/16] Updated the documentation repo location to the offical destination. --- doc/gh-pages.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/gh-pages.py b/doc/gh-pages.py index 815a466d..83e70c1c 100644 --- a/doc/gh-pages.py +++ b/doc/gh-pages.py @@ -9,7 +9,7 @@ If no tag is given, the current output of 'git describe' is used. If given, that is how the resulting directory will be named. In practice, you should use either actual clean tags from a current build or -something like 'current' as a stable URL for the most current version of the """ +something like 'current' as a stable URL for the mest current version of the """ #----------------------------------------------------------------------------- # Imports @@ -30,7 +30,7 @@ from subprocess import Popen, PIPE, CalledProcessError, check_call pages_dir = 'gh-pages' html_dir = 'build/html' pdf_dir = 'build/latex' -pages_repo = 'git@github.com:holtzhau/scikits.image-doc.git' +pages_repo = 'git@github.com:scikits-image/docs.git' #----------------------------------------------------------------------------- # Functions @@ -121,7 +121,7 @@ if __name__ == '__main__': sh('git add %s' % tag) sh2('git commit -m"Updated doc release: %s"' % tag) - print 'Most recent 3 commits:' + print 'Most recent commit:' sys.stdout.flush() sh('git --no-pager log --oneline HEAD~1..') finally: From 01e4fcdd5f03a6d73cdc2116ec32a1a7b8e0eb3d Mon Sep 17 00:00:00 2001 From: Pieter Holtzhausen Date: Fri, 15 Jul 2011 22:14:14 +0200 Subject: [PATCH 16/16] Tag now a prettier version number from setup.py --- doc/gh-pages.py | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/doc/gh-pages.py b/doc/gh-pages.py index 83e70c1c..ddd9d2bb 100644 --- a/doc/gh-pages.py +++ b/doc/gh-pages.py @@ -79,15 +79,13 @@ def init_repo(path): # Script starts #----------------------------------------------------------------------------- if __name__ == '__main__': - # The tag can be given as a positional argument - try: - tag = sys.argv[1] - except IndexError: - try: - #tag = sh2('git describe ') - tag = sh2('git describe --tags') - except CalledProcessError: - tag = "dev" # Fallback + # find the version number from setup.py + setup_lines = open('../setup.py').readlines() + tag = 'vUndefined' + for l in setup_lines: + if l.startswith('VERSION'): + tag = l.split("'")[1] + break startdir = os.getcwd() if not os.path.exists(pages_dir): @@ -100,15 +98,21 @@ if __name__ == '__main__': sh('git pull') cd(startdir) - dest = pjoin(pages_dir, tag) - # don't `make html` here, because gh-pages already depends on html in Makefile - # sh('make html') + dest = os.path.join(pages_dir, tag) # This is pretty unforgiving: we unconditionally nuke the destination # directory, and then copy the html tree in there shutil.rmtree(dest, ignore_errors=True) shutil.copytree(html_dir, dest) + # copy pdf file into tree #shutil.copy(pjoin(pdf_dir, 'scikits.image.pdf'), pjoin(dest, 'scikits.image.pdf')) - + index_html = """ + + %s documentation + + """ % (tag, tag) + with open(os.path.join(pages_dir, "index.html"), 'w') as f: + f.write(index_html) + try: cd(pages_dir) status = sh2('git status | head -1') @@ -117,7 +121,9 @@ if __name__ == '__main__': e = 'On %r, git branch is %r, MUST be "gh-pages"' % (pages_dir, branch) raise RuntimeError(e) - + sh("touch .nojekyll") + sh('git add .nojekyll') + sh('git add index.html') sh('git add %s' % tag) sh2('git commit -m"Updated doc release: %s"' % tag)