-
-
Notifications
You must be signed in to change notification settings - Fork 18.4k
DOC: script to build single docstring page #19840
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
5fd62fc
2766dde
7fe8ac2
13d31b9
1477e63
4e34b09
812eb01
1ca28a0
09c508a
358e08d
2cd4a5d
512d3a6
348cd4f
2acc635
3a57e3e
ebe4a8b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ | |
import argparse | ||
from contextlib import contextmanager | ||
import jinja2 | ||
import webbrowser | ||
|
||
|
||
DOC_PATH = os.path.dirname(os.path.abspath(__file__)) | ||
|
@@ -26,7 +27,7 @@ | |
BUILD_DIRS = ['doctrees', 'html', 'latex', 'plots', '_static', '_templates'] | ||
|
||
|
||
def _generate_index(include_api, single_doc=None): | ||
def _generate_index(include_api=True, single_doc=None): | ||
"""Create index.rst file with the specified sections. | ||
|
||
Parameters | ||
|
@@ -48,6 +49,37 @@ def _generate_index(include_api, single_doc=None): | |
single_doc=single_doc)) | ||
|
||
|
||
def _generate_exclude_pattern(include_api=True, single_doc=None): | ||
|
||
if not include_api: | ||
rst_files = ['api.rst', 'generated/*.rst'] | ||
elif single_doc is not None: | ||
rst_files = [f for f in os.listdir(SOURCE_PATH) | ||
if ((f.endswith('.rst') or f.endswith('.ipynb')) | ||
and (f != 'index.rst') and (f != single_doc))] | ||
rst_files += ['generated/*.rst'] | ||
else: | ||
rst_files = [] | ||
|
||
exclude_patterns = ",".join( | ||
['{!r}'.format(i) for i in ['**.ipynb_checkpoints'] + rst_files]) | ||
|
||
return exclude_patterns | ||
|
||
|
||
def _write_temp_file(classtype, module, function): | ||
|
||
s = """{1}.{2} | ||
================================= | ||
|
||
.. currentmodule:: {1} | ||
|
||
.. auto{0}:: {2}""".format(classtype, module, function) | ||
|
||
with open(os.path.join(SOURCE_PATH, "temp.rst"), 'w') as f: | ||
f.write(s) | ||
|
||
|
||
@contextmanager | ||
def _maybe_exclude_notebooks(): | ||
"""Skip building the notebooks if pandoc is not installed. | ||
|
@@ -96,8 +128,9 @@ class DocBuilder: | |
All public methods of this class can be called as parameters of the | ||
script. | ||
""" | ||
def __init__(self, num_jobs=1): | ||
def __init__(self, num_jobs=1, exclude_patterns=None): | ||
self.num_jobs = num_jobs | ||
self.exclude_patterns = exclude_patterns | ||
|
||
@staticmethod | ||
def _create_build_structure(): | ||
|
@@ -142,8 +175,8 @@ def _sphinx_build(self, kind): | |
self._run_os('sphinx-build', | ||
'-j{}'.format(self.num_jobs), | ||
'-b{}'.format(kind), | ||
'-d{}'.format(os.path.join(BUILD_PATH, | ||
'doctrees')), | ||
'-d{}'.format(os.path.join(BUILD_PATH, 'doctrees')), | ||
# TODO integrate exclude_patterns | ||
SOURCE_PATH, | ||
os.path.join(BUILD_PATH, kind)) | ||
|
||
|
@@ -199,6 +232,23 @@ def zip_html(self): | |
'-q', | ||
*fnames) | ||
|
||
def build_docstring(self): | ||
"""Build single docstring page""" | ||
self._create_build_structure() | ||
|
||
args = ('sphinx-build', | ||
'-bhtml', | ||
'-d{}'.format(os.path.join(BUILD_PATH, 'doctrees')), | ||
'-Dexclude_patterns={}'.format(self.exclude_patterns), | ||
SOURCE_PATH, | ||
os.path.join(BUILD_PATH, 'html'), | ||
os.path.join(SOURCE_PATH, 'temp.rst') | ||
) | ||
# for some reason it does not work with run_os, but it does if I | ||
# directly call the joined command | ||
# self._run_os(*args) | ||
os.system(" ".join(args)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @datapythonista here I had the problem that if I did There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I need to take a look, I think Popen and the functions using it like check_call have some problems if there are spaces in the arguments, may be the exclude patterns need to be between quotes. I'll take a look later. But the reason I wrapped the check_call in a method was exactly to be able to move quickly to os.system or something else. check_call is the preferred way, as it's safer, but it's not the first time I see problems with it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Normally there should be no space in the |
||
|
||
|
||
def main(): | ||
cmds = [method for method in dir(DocBuilder) if not method.startswith('_')] | ||
|
@@ -228,15 +278,34 @@ def main(): | |
type=str, | ||
default=os.path.join(DOC_PATH, '..'), | ||
help='path') | ||
argparser.add_argument('--docstring', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this argument is not used anymore, is it? |
||
metavar='FILENAME', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How much does it complicate things to do There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, not, that wouldn't be to hard I think. Good idea |
||
type=str, | ||
default=None, | ||
help=('method or function name to compile, ' | ||
'e.g. "DataFrame.join"')) | ||
args = argparser.parse_args() | ||
|
||
if args.command not in cmds: | ||
raise ValueError('Unknown command {}. Available options: {}'.format( | ||
args.command, ', '.join(cmds))) | ||
|
||
os.environ['PYTHONPATH'] = args.python_path | ||
_generate_index(not args.no_api, args.single) | ||
getattr(DocBuilder(args.num_jobs), args.command)() | ||
|
||
if args.docstring is not None: | ||
_write_temp_file('method', 'pandas', args.docstring) | ||
exclude_patterns = _generate_exclude_pattern(single_doc='temp.rst') | ||
_generate_index(single_doc='temp.rst') | ||
DocBuilder(args.num_jobs, exclude_patterns).build_docstring() | ||
url = "file://" + os.getcwd() + "/build/html/temp.html" | ||
webbrowser.open(url, new=2) | ||
os.remove('source/temp.rst') | ||
|
||
else: | ||
_generate_index(not args.no_api, args.single) | ||
exclude_patterns = _generate_exclude_pattern( | ||
not args.no_api, args.single) | ||
getattr(DocBuilder(args.num_jobs, exclude_patterns), args.command)() | ||
|
||
|
||
if __name__ == '__main__': | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not major, but the name "include_api" threw me off. Are we including it in output, or are we including it in the list of exclusions, thus excluding it? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah :) I agree it might be confusing, but it is the same keyword name as for
_generate_index
, and there it is more clear thatinclude_api
means to include it in the index.rst file (and thus here, to not put it in the excluded files)