diff --git a/docs/docs_feedback_sphinxext.py b/docs/docs_feedback_sphinxext.py new file mode 100644 index 00000000000..23c8dd0802d --- /dev/null +++ b/docs/docs_feedback_sphinxext.py @@ -0,0 +1,96 @@ +"""A sphinx extension for collecting per doc feedback.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from typing import Dict, List, Union + + from sphinx.application import Sphinx + + +def _modify_rst_document_source_on_read( + app: Sphinx, + docname: str, + source: List[str], +) -> None: + """Add info block to top and bottom of each document source. + + This function modifies RST source in-place by adding an admonition + block at the top and the bottom of each document right after it's + been read from disk preserving :orphan: at top, if present. + """ + admonition_type = 'important' + valid_admonitions = { + 'attention', 'caution', 'danger', 'error', 'hint', + 'important', 'note', 'tip', 'warning', 'admonition', + } + + if admonition_type not in valid_admonitions: + raise ValueError( + 'Expected admonition_type to be one of ' + f'{valid_admonitions} but got {admonition_type}.' + ) + + questions_list = """ + 1. What problem were you trying to solve when you came to this page? + + 2. What content was useful? + + 3. What content was not useful? + """ + questions_list_urlencoded = ( + f""" + 0. Document: {docname}. Page URL: https:// + {questions_list} + """. + rstrip('\r\n\t '). + replace('\r', '%0D'). + replace('\n', '%0A'). + replace(' ', '%20') + ) + + admonition_msg = rf""" + **Did this article help?** + + We are currently doing research to improve pip's documentation + and would love your feedback. + Please `email us`_ and let us know: + + {questions_list} + + .. _email us: + mailto:Docs\ UX\ Team \ + \ + ?subject=[Doc:\ {docname}]\ Pip\ docs\ feedback\ \ + (URL\:\ https\://)\ + &body={questions_list_urlencoded} + """ + orphan_mark = ':orphan:' + info_block = f'.. {admonition_type}::\n\t\t{admonition_msg}\n' + + is_orphan = orphan_mark in source[0] + if is_orphan: + source[0].replace(orphan_mark, '') + else: + orphan_mark = '' + + source[0] = '\n\n'.join(( + orphan_mark, info_block, source[0], info_block, + )) + + +def setup(app: Sphinx) -> Dict[str, Union[bool, str]]: + """Initialize the Sphinx extension. + + This function adds a callback for modifying the document sources + in-place on read. + """ + app.connect('source-read', _modify_rst_document_source_on_read) + + return { + 'parallel_read_safe': True, + 'parallel_write_safe': True, + 'version': 'builtin', + } diff --git a/docs/html/conf.py b/docs/html/conf.py index 2ef2647ce72..6c3e1ba76f7 100644 --- a/docs/html/conf.py +++ b/docs/html/conf.py @@ -30,7 +30,12 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. # extensions = ['sphinx.ext.autodoc'] -extensions = ['sphinx.ext.extlinks', 'pip_sphinxext', 'sphinx.ext.intersphinx'] +extensions = [ + 'sphinx.ext.extlinks', + 'sphinx.ext.intersphinx', + 'docs_feedback_sphinxext', + 'pip_sphinxext', +] # intersphinx intersphinx_cache_limit = 0