PageRenderTime 55ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/doc/source/conf.py

http://github.com/wesm/pandas
Python | 770 lines | 725 code | 14 blank | 31 comment | 24 complexity | 9cbbeb1d0352c66cd5d22f79bfb008b1 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0
  1. # -*- coding: utf-8 -*-
  2. #
  3. # pandas documentation build configuration file, created by
  4. #
  5. # This file is execfile()d with the current directory set to its containing
  6. # dir.
  7. #
  8. # Note that not all possible configuration values are present in this
  9. # autogenerated file.
  10. #
  11. # All configuration values have a default; values that are commented out
  12. # serve to show the default.
  13. import sys
  14. import os
  15. import inspect
  16. import importlib
  17. import logging
  18. import warnings
  19. import jinja2
  20. from sphinx.ext.autosummary import _import_by_name
  21. from numpydoc.docscrape import NumpyDocString
  22. from numpydoc.docscrape_sphinx import SphinxDocString
  23. logger = logging.getLogger(__name__)
  24. # https://github.com/sphinx-doc/sphinx/pull/2325/files
  25. # Workaround for sphinx-build recursion limit overflow:
  26. # pickle.dump(doctree, f, pickle.HIGHEST_PROTOCOL)
  27. # RuntimeError: maximum recursion depth exceeded while pickling an object
  28. #
  29. # Python's default allowed recursion depth is 1000.
  30. sys.setrecursionlimit(5000)
  31. # If extensions (or modules to document with autodoc) are in another directory,
  32. # add these directories to sys.path here. If the directory is relative to the
  33. # documentation root, use os.path.abspath to make it absolute, like shown here.
  34. # sys.path.append(os.path.abspath('.'))
  35. sys.path.insert(0, os.path.abspath('../sphinxext'))
  36. sys.path.extend([
  37. # numpy standard doc extensions
  38. os.path.join(os.path.dirname(__file__),
  39. '..', '../..',
  40. 'sphinxext')
  41. ])
  42. # -- General configuration -----------------------------------------------
  43. # Add any Sphinx extension module names here, as strings. They can be
  44. # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
  45. # sphinxext.
  46. extensions = ['sphinx.ext.autodoc',
  47. 'sphinx.ext.autosummary',
  48. 'sphinx.ext.doctest',
  49. 'sphinx.ext.extlinks',
  50. 'sphinx.ext.todo',
  51. 'numpydoc', # handle NumPy documentation formatted docstrings
  52. 'IPython.sphinxext.ipython_directive',
  53. 'IPython.sphinxext.ipython_console_highlighting',
  54. 'matplotlib.sphinxext.plot_directive',
  55. 'sphinx.ext.intersphinx',
  56. 'sphinx.ext.coverage',
  57. 'sphinx.ext.mathjax',
  58. 'sphinx.ext.ifconfig',
  59. 'sphinx.ext.linkcode',
  60. 'nbsphinx',
  61. 'contributors', # custom pandas extension
  62. ]
  63. exclude_patterns = ['**.ipynb_checkpoints']
  64. try:
  65. import nbconvert
  66. except ImportError:
  67. logger.warn('nbconvert not installed. Skipping notebooks.')
  68. exclude_patterns.append('**/*.ipynb')
  69. else:
  70. try:
  71. nbconvert.utils.pandoc.get_pandoc_version()
  72. except nbconvert.utils.pandoc.PandocMissing:
  73. logger.warn('Pandoc not installed. Skipping notebooks.')
  74. exclude_patterns.append('**/*.ipynb')
  75. # sphinx_pattern can be '-api' to exclude the API pages,
  76. # the path to a file, or a Python object
  77. # (e.g. '10min.rst' or 'pandas.DataFrame.head')
  78. source_path = os.path.dirname(os.path.abspath(__file__))
  79. pattern = os.environ.get('SPHINX_PATTERN')
  80. if pattern:
  81. for dirname, dirs, fnames in os.walk(source_path):
  82. for fname in fnames:
  83. if os.path.splitext(fname)[-1] in ('.rst', '.ipynb'):
  84. fname = os.path.relpath(os.path.join(dirname, fname),
  85. source_path)
  86. if (fname == 'index.rst'
  87. and os.path.abspath(dirname) == source_path):
  88. continue
  89. elif pattern == '-api' and dirname == 'reference':
  90. exclude_patterns.append(fname)
  91. elif pattern != '-api' and fname != pattern:
  92. exclude_patterns.append(fname)
  93. with open(os.path.join(source_path, 'index.rst.template')) as f:
  94. t = jinja2.Template(f.read())
  95. with open(os.path.join(source_path, 'index.rst'), 'w') as f:
  96. f.write(t.render(include_api=pattern is None,
  97. single_doc=(pattern
  98. if pattern is not None and pattern != '-api'
  99. else None)))
  100. autosummary_generate = True if pattern is None else ['index']
  101. # matplotlib plot directive
  102. plot_include_source = True
  103. plot_formats = [("png", 90)]
  104. plot_html_show_formats = False
  105. plot_html_show_source_link = False
  106. plot_pre_code = """import numpy as np
  107. import pandas as pd"""
  108. # Add any paths that contain templates here, relative to this directory.
  109. templates_path = ['../_templates']
  110. # The suffix of source filenames.
  111. source_suffix = [
  112. '.rst',
  113. ]
  114. # The encoding of source files.
  115. source_encoding = 'utf-8'
  116. # The master toctree document.
  117. master_doc = 'index'
  118. # General information about the project.
  119. project = u'pandas'
  120. copyright = u'2008-2014, the pandas development team'
  121. # The version info for the project you're documenting, acts as replacement for
  122. # |version| and |release|, also used in various other places throughout the
  123. # built documents.
  124. #
  125. # The short X.Y version.
  126. import pandas
  127. # version = '%s r%s' % (pandas.__version__, svn_version())
  128. version = str(pandas.__version__)
  129. # The full version, including alpha/beta/rc tags.
  130. release = version
  131. # The language for content autogenerated by Sphinx. Refer to documentation
  132. # for a list of supported languages.
  133. # language = None
  134. # There are two options for replacing |today|: either, you set today to some
  135. # non-false value, then it is used:
  136. # today = ''
  137. # Else, today_fmt is used as the format for a strftime call.
  138. # today_fmt = '%B %d, %Y'
  139. # List of documents that shouldn't be included in the build.
  140. # unused_docs = []
  141. # List of directories, relative to source directory, that shouldn't be searched
  142. # for source files.
  143. exclude_trees = []
  144. # The reST default role (used for this markup: `text`) to use for all
  145. # documents. default_role = None
  146. # If true, '()' will be appended to :func: etc. cross-reference text.
  147. # add_function_parentheses = True
  148. # If true, the current module name will be prepended to all description
  149. # unit titles (such as .. function::).
  150. # add_module_names = True
  151. # If true, sectionauthor and moduleauthor directives will be shown in the
  152. # output. They are ignored by default.
  153. # show_authors = False
  154. # The name of the Pygments (syntax highlighting) style to use.
  155. pygments_style = 'sphinx'
  156. # A list of ignored prefixes for module index sorting.
  157. # modindex_common_prefix = []
  158. # -- Options for HTML output ---------------------------------------------
  159. # The theme to use for HTML and HTML Help pages. Major themes that come with
  160. # Sphinx are currently 'default' and 'sphinxdoc'.
  161. html_theme = 'nature_with_gtoc'
  162. # The style sheet to use for HTML and HTML Help pages. A file of that name
  163. # must exist either in Sphinx' static/ path, or in one of the custom paths
  164. # given in html_static_path.
  165. # html_style = 'statsmodels.css'
  166. # Theme options are theme-specific and customize the look and feel of a theme
  167. # further. For a list of options available for each theme, see the
  168. # documentation.
  169. # html_theme_options = {}
  170. # Add any paths that contain custom themes here, relative to this directory.
  171. html_theme_path = ['themes']
  172. # The name for this set of Sphinx documents. If None, it defaults to
  173. # "<project> v<release> documentation".
  174. # html_title = None
  175. # A shorter title for the navigation bar. Default is the same as html_title.
  176. # html_short_title = None
  177. # The name of an image file (relative to this directory) to place at the top
  178. # of the sidebar.
  179. # html_logo = None
  180. # Add any paths that contain custom static files (such as style sheets) here,
  181. # relative to this directory. They are copied after the builtin static files,
  182. # so a file named "default.css" will overwrite the builtin "default.css".
  183. html_static_path = ['_static']
  184. # The name of an image file (within the static path) to use as favicon of the
  185. # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
  186. # pixels large.
  187. html_favicon = os.path.join(html_static_path[0], 'favicon.ico')
  188. # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
  189. # using the given strftime format.
  190. # html_last_updated_fmt = '%b %d, %Y'
  191. # If true, SmartyPants will be used to convert quotes and dashes to
  192. # typographically correct entities.
  193. # html_use_smartypants = True
  194. # Custom sidebar templates, maps document names to template names.
  195. # html_sidebars = {}
  196. # Additional templates that should be rendered to pages, maps page names to
  197. # template names.
  198. # Add redirect for previously existing API pages
  199. # each item is like `(from_old, to_new)`
  200. # To redirect a class and all its methods, see below
  201. # https://github.com/pandas-dev/pandas/issues/16186
  202. moved_api_pages = [
  203. ('pandas.core.common.isnull', 'pandas.isna'),
  204. ('pandas.core.common.notnull', 'pandas.notna'),
  205. ('pandas.core.reshape.get_dummies', 'pandas.get_dummies'),
  206. ('pandas.tools.merge.concat', 'pandas.concat'),
  207. ('pandas.tools.merge.merge', 'pandas.merge'),
  208. ('pandas.tools.pivot.pivot_table', 'pandas.pivot_table'),
  209. ('pandas.tseries.tools.to_datetime', 'pandas.to_datetime'),
  210. ('pandas.io.clipboard.read_clipboard', 'pandas.read_clipboard'),
  211. ('pandas.io.excel.ExcelFile.parse', 'pandas.ExcelFile.parse'),
  212. ('pandas.io.excel.read_excel', 'pandas.read_excel'),
  213. ('pandas.io.gbq.read_gbq', 'pandas.read_gbq'),
  214. ('pandas.io.html.read_html', 'pandas.read_html'),
  215. ('pandas.io.json.read_json', 'pandas.read_json'),
  216. ('pandas.io.parsers.read_csv', 'pandas.read_csv'),
  217. ('pandas.io.parsers.read_fwf', 'pandas.read_fwf'),
  218. ('pandas.io.parsers.read_table', 'pandas.read_table'),
  219. ('pandas.io.pickle.read_pickle', 'pandas.read_pickle'),
  220. ('pandas.io.pytables.HDFStore.append', 'pandas.HDFStore.append'),
  221. ('pandas.io.pytables.HDFStore.get', 'pandas.HDFStore.get'),
  222. ('pandas.io.pytables.HDFStore.put', 'pandas.HDFStore.put'),
  223. ('pandas.io.pytables.HDFStore.select', 'pandas.HDFStore.select'),
  224. ('pandas.io.pytables.read_hdf', 'pandas.read_hdf'),
  225. ('pandas.io.sql.read_sql', 'pandas.read_sql'),
  226. ('pandas.io.sql.read_frame', 'pandas.read_frame'),
  227. ('pandas.io.sql.write_frame', 'pandas.write_frame'),
  228. ('pandas.io.stata.read_stata', 'pandas.read_stata'),
  229. ]
  230. # Again, tuples of (from_old, to_new)
  231. moved_classes = [
  232. ('pandas.tseries.resample.Resampler', 'pandas.core.resample.Resampler'),
  233. ('pandas.formats.style.Styler', 'pandas.io.formats.style.Styler'),
  234. ]
  235. for old, new in moved_classes:
  236. # the class itself...
  237. moved_api_pages.append((old, new))
  238. mod, classname = new.rsplit('.', 1)
  239. klass = getattr(importlib.import_module(mod), classname)
  240. methods = [x for x in dir(klass)
  241. if not x.startswith('_') or x in ('__iter__', '__array__')]
  242. for method in methods:
  243. # ... and each of its public methods
  244. moved_api_pages.append(
  245. ("{old}.{method}".format(old=old, method=method),
  246. "{new}.{method}".format(new=new, method=method))
  247. )
  248. if pattern is None:
  249. html_additional_pages = {
  250. 'generated/' + page[0]: 'api_redirect.html'
  251. for page in moved_api_pages
  252. }
  253. header = """\
  254. .. currentmodule:: pandas
  255. .. ipython:: python
  256. :suppress:
  257. import numpy as np
  258. import pandas as pd
  259. randn = np.random.randn
  260. np.random.seed(123456)
  261. np.set_printoptions(precision=4, suppress=True)
  262. pd.options.display.max_rows = 15
  263. import os
  264. os.chdir('{}')
  265. """.format(os.path.dirname(os.path.dirname(__file__)))
  266. html_context = {
  267. 'redirects': {old: new for old, new in moved_api_pages},
  268. 'header': header
  269. }
  270. # If false, no module index is generated.
  271. html_use_modindex = True
  272. # If false, no index is generated.
  273. # html_use_index = True
  274. # If true, the index is split into individual pages for each letter.
  275. # html_split_index = False
  276. # If true, links to the reST sources are added to the pages.
  277. # html_show_sourcelink = True
  278. # If true, an OpenSearch description file will be output, and all pages will
  279. # contain a <link> tag referring to it. The value of this option must be the
  280. # base URL from which the finished HTML is served.
  281. # html_use_opensearch = ''
  282. # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
  283. # html_file_suffix = ''
  284. # Output file base name for HTML help builder.
  285. htmlhelp_basename = 'pandas'
  286. # -- Options for nbsphinx ------------------------------------------------
  287. nbsphinx_allow_errors = True
  288. # -- Options for LaTeX output --------------------------------------------
  289. latex_elements = {}
  290. # The paper size ('letter' or 'a4').
  291. # latex_paper_size = 'letter'
  292. # The font size ('10pt', '11pt' or '12pt').
  293. # latex_font_size = '10pt'
  294. # Grouping the document tree into LaTeX files. List of tuples (source start
  295. # file, target name, title, author, documentclass [howto/manual]).
  296. latex_documents = [
  297. ('index', 'pandas.tex',
  298. 'pandas: powerful Python data analysis toolkit',
  299. r'Wes McKinney\n\& PyData Development Team', 'manual'),
  300. ]
  301. # The name of an image file (relative to this directory) to place at the top of
  302. # the title page.
  303. # latex_logo = None
  304. # For "manual" documents, if this is true, then toplevel headings are parts,
  305. # not chapters.
  306. # latex_use_parts = False
  307. # Additional stuff for the LaTeX preamble.
  308. # latex_preamble = ''
  309. # Documents to append as an appendix to all manuals.
  310. # latex_appendices = []
  311. # If false, no module index is generated.
  312. # latex_use_modindex = True
  313. if pattern is None:
  314. intersphinx_mapping = {
  315. 'dateutil': ("https://dateutil.readthedocs.io/en/latest/", None),
  316. 'matplotlib': ('https://matplotlib.org/', None),
  317. 'numpy': ('https://docs.scipy.org/doc/numpy/', None),
  318. 'pandas-gbq': ('https://pandas-gbq.readthedocs.io/en/latest/', None),
  319. 'py': ('https://pylib.readthedocs.io/en/latest/', None),
  320. 'python': ('https://docs.python.org/3/', None),
  321. 'scipy': ('https://docs.scipy.org/doc/scipy/reference/', None),
  322. 'statsmodels': ('http://www.statsmodels.org/devel/', None),
  323. }
  324. # extlinks alias
  325. extlinks = {'issue': ('https://github.com/pandas-dev/pandas/issues/%s',
  326. 'GH'),
  327. 'wiki': ('https://github.com/pandas-dev/pandas/wiki/%s',
  328. 'wiki ')}
  329. # ignore all deprecation warnings from Panel during doc build
  330. # (to avoid the need to add :okwarning: in many places)
  331. warnings.filterwarnings("ignore", message="\nPanel is deprecated",
  332. category=FutureWarning)
  333. ipython_warning_is_error = False
  334. ipython_exec_lines = [
  335. 'import numpy as np',
  336. 'import pandas as pd',
  337. # This ensures correct rendering on system with console encoding != utf8
  338. # (windows). It forces pandas to encode its output reprs using utf8
  339. # wherever the docs are built. The docs' target is the browser, not
  340. # the console, so this is fine.
  341. 'pd.options.display.encoding="utf8"'
  342. ]
  343. def sphinxdocstring_str(self, indent=0, func_role="obj"):
  344. # Pandas displays Attributes section in style like Methods section
  345. # Function is copy of `SphinxDocString.__str__`
  346. ns = {
  347. 'signature': self._str_signature(),
  348. 'index': self._str_index(),
  349. 'summary': self._str_summary(),
  350. 'extended_summary': self._str_extended_summary(),
  351. 'parameters': self._str_param_list('Parameters'),
  352. 'returns': self._str_returns('Returns'),
  353. 'yields': self._str_returns('Yields'),
  354. 'other_parameters': self._str_param_list('Other Parameters'),
  355. 'raises': self._str_param_list('Raises'),
  356. 'warns': self._str_param_list('Warns'),
  357. 'warnings': self._str_warnings(),
  358. 'see_also': self._str_see_also(func_role),
  359. 'notes': self._str_section('Notes'),
  360. 'references': self._str_references(),
  361. 'examples': self._str_examples(),
  362. # Replaced `self._str_param_list('Attributes', fake_autosummary=True)`
  363. # with `self._str_member_list('Attributes')`
  364. 'attributes': self._str_member_list('Attributes'),
  365. 'methods': self._str_member_list('Methods'),
  366. }
  367. ns = {k: '\n'.join(v) for k, v in ns.items()}
  368. rendered = self.template.render(**ns)
  369. return '\n'.join(self._str_indent(rendered.split('\n'), indent))
  370. SphinxDocString.__str__ = sphinxdocstring_str
  371. # Fix "WARNING: Inline strong start-string without end-string."
  372. # PR #155 "Escape the * in *args and **kwargs" from numpydoc
  373. # Can be removed after PR merges in v0.9.0
  374. def decorate_process_param(func):
  375. def _escape_args_and_kwargs(name):
  376. if name[:2] == '**':
  377. return r'\*\*' + name[2:]
  378. elif name[:1] == '*':
  379. return r'\*' + name[1:]
  380. else:
  381. return name
  382. def func_wrapper(self, param, desc, fake_autosummary):
  383. param = _escape_args_and_kwargs(param.strip())
  384. return func(self, param, desc, fake_autosummary)
  385. return func_wrapper
  386. func = SphinxDocString._process_param
  387. SphinxDocString._process_param = decorate_process_param(func)
  388. # Add custom Documenter to handle attributes/methods of an AccessorProperty
  389. # eg pandas.Series.str and pandas.Series.dt (see GH9322)
  390. import sphinx
  391. from sphinx.util import rpartition
  392. from sphinx.ext.autodoc import (
  393. Documenter, MethodDocumenter, AttributeDocumenter)
  394. from sphinx.ext.autosummary import Autosummary
  395. class AccessorDocumenter(MethodDocumenter):
  396. """
  397. Specialized Documenter subclass for accessors.
  398. """
  399. objtype = 'accessor'
  400. directivetype = 'method'
  401. # lower than MethodDocumenter so this is not chosen for normal methods
  402. priority = 0.6
  403. def format_signature(self):
  404. # this method gives an error/warning for the accessors, therefore
  405. # overriding it (accessor has no arguments)
  406. return ''
  407. class AccessorLevelDocumenter(Documenter):
  408. """
  409. Specialized Documenter subclass for objects on accessor level (methods,
  410. attributes).
  411. """
  412. # This is the simple straightforward version
  413. # modname is None, base the last elements (eg 'hour')
  414. # and path the part before (eg 'Series.dt')
  415. # def resolve_name(self, modname, parents, path, base):
  416. # modname = 'pandas'
  417. # mod_cls = path.rstrip('.')
  418. # mod_cls = mod_cls.split('.')
  419. #
  420. # return modname, mod_cls + [base]
  421. def resolve_name(self, modname, parents, path, base):
  422. if modname is None:
  423. if path:
  424. mod_cls = path.rstrip('.')
  425. else:
  426. mod_cls = None
  427. # if documenting a class-level object without path,
  428. # there must be a current class, either from a parent
  429. # auto directive ...
  430. mod_cls = self.env.temp_data.get('autodoc:class')
  431. # ... or from a class directive
  432. if mod_cls is None:
  433. mod_cls = self.env.temp_data.get('py:class')
  434. # ... if still None, there's no way to know
  435. if mod_cls is None:
  436. return None, []
  437. # HACK: this is added in comparison to ClassLevelDocumenter
  438. # mod_cls still exists of class.accessor, so an extra
  439. # rpartition is needed
  440. modname, accessor = rpartition(mod_cls, '.')
  441. modname, cls = rpartition(modname, '.')
  442. parents = [cls, accessor]
  443. # if the module name is still missing, get it like above
  444. if not modname:
  445. modname = self.env.temp_data.get('autodoc:module')
  446. if not modname:
  447. if sphinx.__version__ > '1.3':
  448. modname = self.env.ref_context.get('py:module')
  449. else:
  450. modname = self.env.temp_data.get('py:module')
  451. # ... else, it stays None, which means invalid
  452. return modname, parents + [base]
  453. class AccessorAttributeDocumenter(AccessorLevelDocumenter,
  454. AttributeDocumenter):
  455. objtype = 'accessorattribute'
  456. directivetype = 'attribute'
  457. # lower than AttributeDocumenter so this is not chosen for normal
  458. # attributes
  459. priority = 0.6
  460. class AccessorMethodDocumenter(AccessorLevelDocumenter, MethodDocumenter):
  461. objtype = 'accessormethod'
  462. directivetype = 'method'
  463. # lower than MethodDocumenter so this is not chosen for normal methods
  464. priority = 0.6
  465. class AccessorCallableDocumenter(AccessorLevelDocumenter, MethodDocumenter):
  466. """
  467. This documenter lets us removes .__call__ from the method signature for
  468. callable accessors like Series.plot
  469. """
  470. objtype = 'accessorcallable'
  471. directivetype = 'method'
  472. # lower than MethodDocumenter; otherwise the doc build prints warnings
  473. priority = 0.5
  474. def format_name(self):
  475. return MethodDocumenter.format_name(self).rstrip('.__call__')
  476. class PandasAutosummary(Autosummary):
  477. """
  478. This alternative autosummary class lets us override the table summary for
  479. Series.plot and DataFrame.plot in the API docs.
  480. """
  481. def _replace_pandas_items(self, display_name, sig, summary, real_name):
  482. # this a hack: ideally we should extract the signature from the
  483. # .__call__ method instead of hard coding this
  484. if display_name == 'DataFrame.plot':
  485. sig = '([x, y, kind, ax, ....])'
  486. summary = 'DataFrame plotting accessor and method'
  487. elif display_name == 'Series.plot':
  488. sig = '([kind, ax, figsize, ....])'
  489. summary = 'Series plotting accessor and method'
  490. return (display_name, sig, summary, real_name)
  491. @staticmethod
  492. def _is_deprecated(real_name):
  493. try:
  494. obj, parent, modname = _import_by_name(real_name)
  495. except ImportError:
  496. return False
  497. doc = NumpyDocString(obj.__doc__ or '')
  498. summary = ''.join(doc['Summary'] + doc['Extended Summary'])
  499. return '.. deprecated::' in summary
  500. def _add_deprecation_prefixes(self, items):
  501. for item in items:
  502. display_name, sig, summary, real_name = item
  503. if self._is_deprecated(real_name):
  504. summary = '(DEPRECATED) %s' % summary
  505. yield display_name, sig, summary, real_name
  506. def get_items(self, names):
  507. items = Autosummary.get_items(self, names)
  508. items = [self._replace_pandas_items(*item) for item in items]
  509. items = list(self._add_deprecation_prefixes(items))
  510. return items
  511. # based on numpy doc/source/conf.py
  512. def linkcode_resolve(domain, info):
  513. """
  514. Determine the URL corresponding to Python object
  515. """
  516. if domain != 'py':
  517. return None
  518. modname = info['module']
  519. fullname = info['fullname']
  520. submod = sys.modules.get(modname)
  521. if submod is None:
  522. return None
  523. obj = submod
  524. for part in fullname.split('.'):
  525. try:
  526. obj = getattr(obj, part)
  527. except AttributeError:
  528. return None
  529. try:
  530. # inspect.unwrap() was added in Python version 3.4
  531. if sys.version_info >= (3, 5):
  532. fn = inspect.getsourcefile(inspect.unwrap(obj))
  533. else:
  534. fn = inspect.getsourcefile(obj)
  535. except TypeError:
  536. fn = None
  537. if not fn:
  538. return None
  539. try:
  540. source, lineno = inspect.getsourcelines(obj)
  541. except OSError:
  542. lineno = None
  543. if lineno:
  544. linespec = "#L{:d}-L{:d}".format(lineno, lineno + len(source) - 1)
  545. else:
  546. linespec = ""
  547. fn = os.path.relpath(fn, start=os.path.dirname(pandas.__file__))
  548. if '+' in pandas.__version__:
  549. return ("http://github.com/pandas-dev/pandas/blob/master/pandas/"
  550. "{}{}".format(fn, linespec))
  551. else:
  552. return ("http://github.com/pandas-dev/pandas/blob/"
  553. "v{}/pandas/{}{}".format(pandas.__version__, fn, linespec))
  554. # remove the docstring of the flags attribute (inherited from numpy ndarray)
  555. # because these give doc build errors (see GH issue 5331)
  556. def remove_flags_docstring(app, what, name, obj, options, lines):
  557. if what == "attribute" and name.endswith(".flags"):
  558. del lines[:]
  559. def process_class_docstrings(app, what, name, obj, options, lines):
  560. """
  561. For those classes for which we use ::
  562. :template: autosummary/class_without_autosummary.rst
  563. the documented attributes/methods have to be listed in the class
  564. docstring. However, if one of those lists is empty, we use 'None',
  565. which then generates warnings in sphinx / ugly html output.
  566. This "autodoc-process-docstring" event connector removes that part
  567. from the processed docstring.
  568. """
  569. if what == "class":
  570. joined = '\n'.join(lines)
  571. templates = [
  572. """.. rubric:: Attributes
  573. .. autosummary::
  574. :toctree:
  575. None
  576. """,
  577. """.. rubric:: Methods
  578. .. autosummary::
  579. :toctree:
  580. None
  581. """
  582. ]
  583. for template in templates:
  584. if template in joined:
  585. joined = joined.replace(template, '')
  586. lines[:] = joined.split('\n')
  587. suppress_warnings = [
  588. # We "overwrite" autosummary with our PandasAutosummary, but
  589. # still want the regular autosummary setup to run. So we just
  590. # suppress this warning.
  591. 'app.add_directive'
  592. ]
  593. if pattern:
  594. # When building a single document we don't want to warn because references
  595. # to other documents are unknown, as it's expected
  596. suppress_warnings.append('ref.ref')
  597. def rstjinja(app, docname, source):
  598. """
  599. Render our pages as a jinja template for fancy templating goodness.
  600. """
  601. # http://ericholscher.com/blog/2016/jul/25/integrating-jinja-rst-sphinx/
  602. # Make sure we're outputting HTML
  603. if app.builder.format != 'html':
  604. return
  605. src = source[0]
  606. rendered = app.builder.templates.render_string(
  607. src, app.config.html_context
  608. )
  609. source[0] = rendered
  610. def setup(app):
  611. app.connect("source-read", rstjinja)
  612. app.connect("autodoc-process-docstring", remove_flags_docstring)
  613. app.connect("autodoc-process-docstring", process_class_docstrings)
  614. app.add_autodocumenter(AccessorDocumenter)
  615. app.add_autodocumenter(AccessorAttributeDocumenter)
  616. app.add_autodocumenter(AccessorMethodDocumenter)
  617. app.add_autodocumenter(AccessorCallableDocumenter)
  618. app.add_directive('autosummary', PandasAutosummary)