mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-31 12:41:20 +08:00
Merge documentation build system fixes by Pieter Holtzhausen and Tony Yu.
This commit is contained in:
+19
-15
@@ -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,8 @@ help:
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
|
||||
clean:
|
||||
-rm -rf build/*
|
||||
-rm -rf $(DEST)/*
|
||||
-rm -rf source/api
|
||||
|
||||
api:
|
||||
mkdir -p source/api
|
||||
@@ -37,33 +38,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 +73,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 +82,33 @@ 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."
|
||||
|
||||
gh-pages:
|
||||
python gh-pages.py
|
||||
|
||||
+31
-30
@@ -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<role>\w+):`(?P<name>[a-zA-Z0-9_.-]+)`|"
|
||||
r" (?P<name2>[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]
|
||||
|
||||
@@ -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)
|
||||
|
||||
+53
-81
@@ -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,73 +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:
|
||||
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
|
||||
@@ -169,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)
|
||||
|
||||
+580
-392
File diff suppressed because it is too large
Load Diff
+138
@@ -0,0 +1,138 @@
|
||||
#!/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 mest 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:scikits-image/docs.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__':
|
||||
# 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):
|
||||
# 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 = 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 = """
|
||||
<html><body>
|
||||
<a href="%s/index.html">%s documentation</a>
|
||||
</body></html>
|
||||
""" % (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')
|
||||
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("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)
|
||||
|
||||
print 'Most recent commit:'
|
||||
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'"
|
||||
+4
-4
@@ -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/* .
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
.. AUTO-GENERATED FILE -- DO NOT EDIT!
|
||||
|
||||
API Reference
|
||||
=============
|
||||
|
||||
.. toctree::
|
||||
|
||||
scikits.image
|
||||
scikits.image.color
|
||||
scikits.image.filter
|
||||
scikits.image.graph
|
||||
scikits.image.io
|
||||
scikits.image.morphology
|
||||
scikits.image.opencv
|
||||
scikits.image.transform
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,45 +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.inverse
|
||||
scikits.image.filter.median_filter
|
||||
scikits.image.filter.wiener
|
||||
|
||||
inverse
|
||||
-------
|
||||
|
||||
.. autofunction:: scikits.image.filter.inverse
|
||||
|
||||
median_filter
|
||||
-------------
|
||||
|
||||
.. autofunction:: scikits.image.filter.median_filter
|
||||
|
||||
wiener
|
||||
------
|
||||
|
||||
.. autofunction:: scikits.image.filter.wiener
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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`_.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.. _using-git:
|
||||
|
||||
Working with *scikits.image* source code
|
||||
======================================
|
||||
========================================
|
||||
|
||||
Contents:
|
||||
|
||||
|
||||
+13
-6
@@ -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')
|
||||
@@ -194,14 +200,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 \
|
||||
|
||||
Reference in New Issue
Block a user