diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0afa776e702..0521f261f7b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,7 +22,6 @@ repos: - id: black exclude: | (?x) - ^docs/| ^src/pip/_internal/commands| ^src/pip/_internal/index| ^src/pip/_internal/models| diff --git a/MANIFEST.in b/MANIFEST.in index 24d4553785b..9148af0b652 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -22,7 +22,7 @@ exclude noxfile.py recursive-include src/pip/_vendor *.pem recursive-include src/pip/_vendor py.typed -recursive-include docs *.css *.rst *.py +recursive-include docs *.css *.py *.rst *.md exclude src/pip/_vendor/six exclude src/pip/_vendor/six/moves diff --git a/docs/docs_feedback_sphinxext.py b/docs/docs_feedback_sphinxext.py deleted file mode 100644 index d0ff1f03da1..00000000000 --- a/docs/docs_feedback_sphinxext.py +++ /dev/null @@ -1,160 +0,0 @@ -"""A sphinx extension for collecting per doc feedback.""" - -from __future__ import annotations - -from itertools import chain -from typing import Dict, List, Union - -from sphinx.application import Sphinx - -DEFAULT_DOC_LINES_THRESHOLD = 250 -RST_INDENT = 4 -EMAIL_INDENT = 6 - - -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 = app.config.docs_feedback_admonition_type - big_doc_lines = app.config.docs_feedback_big_doc_lines - escaped_email = app.config.docs_feedback_email.replace(' ', r'\ ') - excluded_documents = set(app.config.docs_feedback_excluded_documents) - questions_list = app.config.docs_feedback_questions_list - - valid_admonitions = { - 'attention', 'caution', 'danger', 'error', 'hint', - 'important', 'note', 'tip', 'warning', 'admonition', - } - - if admonition_type not in valid_admonitions: - raise ValueError( - 'Expected `docs_feedback_admonition_type` to be one of ' - f'{valid_admonitions} but got {admonition_type}.' - ) - - if not questions_list: - raise ValueError( - 'Expected `docs_feedback_questions_list` to list questions ' - 'but got none.' - ) - - if docname in excluded_documents: - # NOTE: Completely ignore any document - # NOTE: listed in 'docs_feedback_excluded_documents'. - return - - is_doc_big = source[0].count('\n') >= big_doc_lines - - questions_list_rst = '\n'.join( - f'{" " * RST_INDENT}{number!s}. {question}' - for number, question in enumerate(questions_list, 1) - ) - questions_list_urlencoded = ( - '\n'.join( - f'\n{" " * RST_INDENT}{number!s}. {question} ' - for number, question in enumerate( - chain( - (f'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{{let_us_know_ending}} - -{{questions_list_rst}} - - .. _email us: - mailto:{escaped_email}\ - ?subject=[Doc:\ {docname}]\ Pip\ docs\ feedback\ \ - (URL\:\ https\://)\ - &body={questions_list_urlencoded} - """ - let_us_know_ending = ':' - - info_block_bottom = ( - f'.. {admonition_type}::\n\t\t{admonition_msg.format_map(locals())}\n' - ) - - questions_list_rst = '' - let_us_know_ending = ( - ' why you came to this page and what on it helped ' - 'you and what did not. ' - '(:issue:`Read more about this research <8517>`)' - ) - info_block_top = '' if is_doc_big else ( - f'.. {admonition_type}::\n\t\t{admonition_msg.format_map(locals())}\n' - ) - - orphan_mark = ':orphan:' - is_orphan = orphan_mark in source[0] - if is_orphan: - source[0] = source[0].replace(orphan_mark, '') - else: - orphan_mark = '' - - source[0] = '\n\n'.join(( - orphan_mark, info_block_top, source[0], info_block_bottom, - )) - - -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. - - It also declares the extension settings changable via :file:`conf.py`. - """ - rebuild_trigger = 'html' # rebuild full html on settings change - app.add_config_value( - 'docs_feedback_admonition_type', - default='important', - rebuild=rebuild_trigger, - ) - app.add_config_value( - 'docs_feedback_big_doc_lines', - default=DEFAULT_DOC_LINES_THRESHOLD, - rebuild=rebuild_trigger, - ) - app.add_config_value( - 'docs_feedback_email', - default='Docs UX Team ', - rebuild=rebuild_trigger, - ) - app.add_config_value( - 'docs_feedback_excluded_documents', - default=set(), - rebuild=rebuild_trigger, - ) - app.add_config_value( - 'docs_feedback_questions_list', - default=(), - rebuild=rebuild_trigger, - ) - - 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 2efb7135892..14ea84bfba9 100644 --- a/docs/html/conf.py +++ b/docs/html/conf.py @@ -1,13 +1,4 @@ -# pip documentation build configuration file, created by -# sphinx-quickstart on Tue Apr 22 22:08:49 2008 -# -# This file is execfile()d with the current directory set to its containing dir -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. +"""Sphinx configuration file for pip's documentation.""" import glob import os @@ -15,311 +6,122 @@ import re import sys -on_rtd = os.environ.get('READTHEDOCS', None) == 'True' - +# Add the docs/ directory to sys.path, because pip_sphinxext.py is there. docs_dir = os.path.dirname(os.path.dirname(__file__)) -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, docs_dir) -# sys.path.append(os.path.join(os.path.dirname(__file__), '../')) -# -- General configuration ---------------------------------------------------- +# -- General configuration ------------------------------------------------------------ -# 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 = [ - # native: - 'sphinx.ext.extlinks', - 'sphinx.ext.intersphinx', - # third-party: - 'sphinx_inline_tabs', - 'sphinxcontrib.towncrier', - # in-tree: - 'docs_feedback_sphinxext', - 'pip_sphinxext', + # first-party extensions + "sphinx.ext.autodoc", + "sphinx.ext.todo", + "sphinx.ext.extlinks", + "sphinx.ext.intersphinx", + # our extensions + "pip_sphinxext", + # third-party extensions + "myst_parser", + "sphinx_copybutton", + "sphinx_inline_tabs", + "sphinxcontrib.towncrier", ] -# intersphinx -intersphinx_cache_limit = 0 -intersphinx_mapping = { - 'pypug': ('https://packaging.python.org/', None), - 'pypa': ('https://www.pypa.io/en/latest/', None), -} - - -# Add any paths that contain templates here, relative to this directory. -templates_path = [] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -# source_encoding = 'utf-8' - -# The master toctree document. -master_doc = 'index' - # General information about the project. -project = 'pip' -copyright = '2008-2020, PyPA' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. - -version = release = 'dev' - -# Readthedocs seems to install pip as an egg (via setup.py install) which -# is somehow resulting in "import pip" picking up an older copy of pip. -# Rather than trying to force RTD to install pip properly, we'll simply -# read the version direct from the __init__.py file. (Yes, this is -# fragile, but it works...) - -pip_init = os.path.join(docs_dir, '..', 'src', 'pip', '__init__.py') -with open(pip_init) as f: +project = "pip" +copyright = "2008-2020, PyPA" + +# Find the version and release information. +# We have a single source of truth for our version number: pip's __init__.py file. +# This next bit of code reads from it. +file_with_version = os.path.join(docs_dir, "..", "src", "pip", "__init__.py") +with open(file_with_version) as f: for line in f: m = re.match(r'__version__ = "(.*)"', line) if m: __version__ = m.group(1) # The short X.Y version. - version = '.'.join(__version__.split('.')[:2]) + version = ".".join(__version__.split(".")[:2]) # The full version, including alpha/beta/rc tags. release = __version__ break + else: # AKA no-break + version = release = "dev" -# We have this here because readthedocs plays tricks sometimes and there seems -# to be a heisenbug, related to the version of pip discovered. This is here to -# help debug that if someone decides to do that in the future. print("pip version:", version) print("pip release:", release) -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -# today = '' -# Else, today_fmt is used as the format for a strftime call. -today_fmt = '%B %d, %Y' - -# List of documents that shouldn't be included in the build. -# unused_docs = [] - -# List of directories, relative to source directory, that shouldn't be searched -# for source files. -exclude_patterns = ['build/'] - -# The reST default role (used for this markup: `text`) to use for all documents -# default_role = None +# -- Options for smartquotes ---------------------------------------------------------- -# If true, '()' will be appended to :func: etc. cross-reference text. -# add_function_parentheses = True +# Disable the conversion of dashes so that long options like "--find-links" won't +# render as "-find-links" if included in the text.The default of "qDe" converts normal +# quote characters ('"' and "'"), en and em dashes ("--" and "---"), and ellipses "..." +smartquotes_action = "qe" -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -# add_module_names = True +# -- Options for intersphinx ---------------------------------------------------------- -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -# show_authors = False +intersphinx_mapping = { + "python": ("https://docs.python.org/3", None), + "pypug": ("https://packaging.python.org", None), +} -# A list of ignored prefixes for module index sorting. -# modindex_common_prefix = [] +# -- Options for extlinks ------------------------------------------------------------- extlinks = { - 'issue': ('https://github.com/pypa/pip/issues/%s', '#'), - 'pull': ('https://github.com/pypa/pip/pull/%s', 'PR #'), - 'pypi': ('https://pypi.org/project/%s/', ''), + "issue": ("https://github.com/pypa/pip/issues/%s", "#"), + "pull": ("https://github.com/pypa/pip/pull/%s", "PR #"), + "pypi": ("https://pypi.org/project/%s/", ""), } -# Turn off sphinx build warnings because of sphinx tabs during man pages build -sphinx_tabs_nowarn = True - -# -- Options for HTML output -------------------------------------------------- +# -- Options for towncrier_draft extension -------------------------------------------- -# The theme to use for HTML and HTML Help pages. Major themes that come with -# Sphinx are currently 'default' and 'sphinxdoc'. -html_theme = "furo" - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -html_theme_options = {} +towncrier_draft_autoversion_mode = "draft" # or: 'sphinx-release', 'sphinx-version' +towncrier_draft_include_empty = True +towncrier_draft_working_directory = pathlib.Path(docs_dir).parent +# Not yet supported: towncrier_draft_config_path = 'pyproject.toml' # relative to cwd -# Add any paths that contain custom themes here, relative to this directory. +# -- Options for HTML ----------------------------------------------------------------- -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". +html_theme = "furo" html_title = f"{project} documentation v{release}" -# A shorter title for the navigation bar. Default is the same as html_title. -# html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -# html_logo = '_static/piplogo.png' - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -# html_favicon = 'favicon.png' - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -html_last_updated_fmt = '%b %d, %Y' - -# If true, the Docutils Smart Quotes transform (originally based on -# SmartyPants) will be used to convert characters like quotes and dashes -# to typographically correct entities. The default is True. -smartquotes = True - -# This string, for use with Docutils 0.14 or later, customizes the -# SmartQuotes transform. The default of "qDe" converts normal quote -# characters ('"' and "'"), en and em dashes ("--" and "---"), and -# ellipses "...". -# For now, we disable the conversion of dashes so that long options -# like "--find-links" won't render as "-find-links" if included in the -# text in places where monospaced type can't be used. For example, backticks -# can't be used inside roles like :ref:`--no-index <--no-index>` because -# of nesting. -smartquotes_action = "qe" - -# Custom sidebar templates, maps document names to template names. -html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {} - -# If false, no module index is generated. +# Disable the generation of the various indexes html_use_modindex = False - -# If false, no index is generated. html_use_index = False -# If true, the index is split into individual pages for each letter. -# html_split_index = False - -# If true, links to the reST sources are added to the pages. -html_show_sourcelink = False - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -# html_use_opensearch = '' - -# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). -# html_file_suffix = '' - -# Output file base name for HTML help builder. -htmlhelp_basename = 'pipdocs' - - -# -- Options for LaTeX output ------------------------------------------------- - -# The paper size ('letter' or 'a4'). -# latex_paper_size = 'letter' - -# The font size ('10pt', '11pt' or '12pt'). -# latex_font_size = '10pt' - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]) -latex_documents = [ - ( - 'index', - 'pip.tex', - 'pip Documentation', - 'pip developers', - 'manual', - ), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -# latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -# latex_use_parts = False +# -- Options for Manual Pages --------------------------------------------------------- -# Additional stuff for the LaTeX preamble. -# latex_preamble = '' - -# Documents to append as an appendix to all manuals. -# latex_appendices = [] - -# If false, no module index is generated. -# latex_use_modindex = True - -# -- Options for Manual Pages ------------------------------------------------- # List of manual pages generated -man_pages = [ - ( - 'index', - 'pip', - 'package manager for Python packages', - 'pip developers', - 1 - ) -] - - -def to_document_name(path, base_dir): - """Convert a provided path to a Sphinx "document name". - """ - relative_path = os.path.relpath(path, base_dir) - root, _ = os.path.splitext(relative_path) - return root.replace(os.sep, '/') - - -# Here, we crawl the entire man/commands/ directory and list every file with -# appropriate name and details -man_dir = os.path.join(docs_dir, 'man') -raw_subcommands = glob.glob(os.path.join(man_dir, 'commands/*.rst')) -if not raw_subcommands: - raise FileNotFoundError( - 'The individual subcommand manpages could not be found!' - ) -for fname in raw_subcommands: - fname_base = to_document_name(fname, man_dir) - outname = 'pip-' + fname_base.split('/')[1] - description = 'description of {} command'.format( - outname.replace('-', ' ') - ) - - man_pages.append((fname_base, outname, description, 'pip developers', 1)) - -# -- Options for docs_feedback_sphinxext -------------------------------------- - -# NOTE: Must be one of 'attention', 'caution', 'danger', 'error', 'hint', -# NOTE: 'important', 'note', 'tip', 'warning' or 'admonition'. -docs_feedback_admonition_type = 'important' -docs_feedback_big_doc_lines = 50 # bigger docs will have a banner on top -docs_feedback_email = 'Docs UX Team ' -docs_feedback_excluded_documents = { # these won't have any banners - 'news', 'reference/index', -} -docs_feedback_questions_list = ( - 'What problem were you trying to solve when you came to this page?', - 'What content was useful?', - 'What content was not useful?', -) - -# -- Options for towncrier_draft extension ----------------------------------- - -towncrier_draft_autoversion_mode = 'draft' # or: 'sphinx-release', 'sphinx-version' -towncrier_draft_include_empty = False -towncrier_draft_working_directory = pathlib.Path(docs_dir).parent -# Not yet supported: towncrier_draft_config_path = 'pyproject.toml' # relative to cwd +def determine_man_pages(): + """Determine which man pages need to be generated.""" + + def to_document_name(path, base_dir): + """Convert a provided path to a Sphinx "document name".""" + relative_path = os.path.relpath(path, base_dir) + root, _ = os.path.splitext(relative_path) + return root.replace(os.sep, "/") + + # Crawl the entire man/commands/ directory and list every file with appropriate + # name and details. + man_dir = os.path.join(docs_dir, "man") + raw_subcommands = glob.glob(os.path.join(man_dir, "commands/*.rst")) + if not raw_subcommands: + raise FileNotFoundError( + "The individual subcommand manpages could not be found!" + ) + + retval = [ + ("index", "pip", "package manager for Python packages", "pip developers", 1), + ] + for fname in raw_subcommands: + fname_base = to_document_name(fname, man_dir) + outname = "pip-" + fname_base.split("/")[1] + description = "description of {} command".format(outname.replace("-", " ")) + + retval.append((fname_base, outname, description, "pip developers", 1)) + + return retval + + +man_pages = determine_man_pages() diff --git a/docs/pip_sphinxext.py b/docs/pip_sphinxext.py index 1ce526e0d6c..8e5cc7a2cc5 100644 --- a/docs/pip_sphinxext.py +++ b/docs/pip_sphinxext.py @@ -1,12 +1,13 @@ """pip sphinx extensions""" import optparse +import re import sys from textwrap import dedent from docutils import nodes from docutils.parsers import rst -from docutils.statemachine import ViewList +from docutils.statemachine import StringList, ViewList from pip._internal.cli import cmdoptions from pip._internal.commands import commands_dict, create_command @@ -19,14 +20,12 @@ class PipCommandUsage(rst.Directive): def run(self): cmd = create_command(self.arguments[0]) - cmd_prefix = 'python -m pip' + cmd_prefix = "python -m pip" if len(self.arguments) > 1: cmd_prefix = " ".join(self.arguments[1:]) cmd_prefix = cmd_prefix.strip('"') cmd_prefix = cmd_prefix.strip("'") - usage = dedent( - cmd.usage.replace('%prog', f'{cmd_prefix} {cmd.name}') - ).strip() + usage = dedent(cmd.usage.replace("%prog", f"{cmd_prefix} {cmd.name}")).strip() node = nodes.literal_block(usage, usage) return [node] @@ -40,19 +39,18 @@ def run(self): desc = ViewList() cmd = create_command(self.arguments[0]) description = dedent(cmd.__doc__) - for line in description.split('\n'): + for line in description.split("\n"): desc.append(line, "") self.state.nested_parse(desc, 0, node) return [node] class PipOptions(rst.Directive): - def _format_option(self, option, cmd_name=None): bookmark_line = ( f".. _`{cmd_name}_{option._long_opts[0]}`:" - if cmd_name else - f".. _`{option._long_opts[0]}`:" + if cmd_name + else f".. _`{option._long_opts[0]}`:" ) line = ".. option:: " if option._short_opts: @@ -65,7 +63,7 @@ def _format_option(self, option, cmd_name=None): metavar = option.metavar or option.dest.lower() line += f" <{metavar.lower()}>" # fix defaults - opt_help = option.help.replace('%default', str(option.default)) + opt_help = option.help.replace("%default", str(option.default)) # fix paths with sys.prefix opt_help = opt_help.replace(sys.prefix, "") return [bookmark_line, "", line, "", " " + opt_help, ""] @@ -88,9 +86,7 @@ def run(self): class PipGeneralOptions(PipOptions): def process_options(self): - self._format_options( - [o() for o in cmdoptions.general_group['options']] - ) + self._format_options([o() for o in cmdoptions.general_group["options"]]) class PipIndexOptions(PipOptions): @@ -99,7 +95,7 @@ class PipIndexOptions(PipOptions): def process_options(self): cmd_name = self.arguments[0] self._format_options( - [o() for o in cmdoptions.index_group['options']], + [o() for o in cmdoptions.index_group["options"]], cmd_name=cmd_name, ) @@ -116,49 +112,127 @@ def process_options(self): class PipReqFileOptionsReference(PipOptions): - def determine_opt_prefix(self, opt_name): for command in commands_dict: cmd = create_command(command) if cmd.cmd_opts.has_option(opt_name): return command - raise KeyError(f'Could not identify prefix of opt {opt_name}') + raise KeyError(f"Could not identify prefix of opt {opt_name}") def process_options(self): for option in SUPPORTED_OPTIONS: - if getattr(option, 'deprecated', False): + if getattr(option, "deprecated", False): continue opt = option() opt_name = opt._long_opts[0] if opt._short_opts: - short_opt_name = '{}, '.format(opt._short_opts[0]) + short_opt_name = "{}, ".format(opt._short_opts[0]) else: - short_opt_name = '' + short_opt_name = "" - if option in cmdoptions.general_group['options']: - prefix = '' + if option in cmdoptions.general_group["options"]: + prefix = "" else: - prefix = '{}_'.format(self.determine_opt_prefix(opt_name)) + prefix = "{}_".format(self.determine_opt_prefix(opt_name)) self.view_list.append( - '* :ref:`{short}{long}<{prefix}{opt_name}>`'.format( + "* :ref:`{short}{long}<{prefix}{opt_name}>`".format( short=short_opt_name, long=opt_name, prefix=prefix, - opt_name=opt_name + opt_name=opt_name, ), - "\n" + "\n", ) +class PipCLIDirective(rst.Directive): + """ + - Only works when used in a MyST document. + - Requires sphinx-inline-tabs' tab directive. + """ + + has_content = True + optional_arguments = 1 + + def run(self): + node = nodes.paragraph() + node.document = self.state.document + + os_variants = { + "Linux": { + "highlighter": "console", + "executable": "python", + "prompt": "$", + }, + "MacOS": { + "highlighter": "console", + "executable": "python", + "prompt": "$", + }, + "Windows": { + "highlighter": "doscon", + "executable": "py", + "prompt": "C:>", + }, + } + + if self.arguments: + assert self.arguments == ["in-a-venv"] + in_virtual_environment = True + else: + in_virtual_environment = False + + lines = [] + # Create a tab for each OS + for os, variant in os_variants.items(): + + # Unpack the values + prompt = variant["prompt"] + highlighter = variant["highlighter"] + if in_virtual_environment: + executable = "python" + pip_spelling = "pip" + else: + executable = variant["executable"] + pip_spelling = f"{executable} -m pip" + + # Substitute the various "prompts" into the correct variants + substitution_pipeline = [ + ( + r"(^|(?<=\n))\$ python", + f"{prompt} {executable}", + ), + ( + r"(^|(?<=\n))\$ pip", + f"{prompt} {pip_spelling}", + ), + ] + content = self.block_text + for pattern, substitution in substitution_pipeline: + content = re.sub(pattern, substitution, content) + + # Write the tab + lines.append(f"````{{tab}} {os}") + lines.append(f"```{highlighter}") + lines.append(f"{content}") + lines.append("```") + lines.append("````") + + string_list = StringList(lines) + self.state.nested_parse(string_list, 0, node) + return [node] + + def setup(app): - app.add_directive('pip-command-usage', PipCommandUsage) - app.add_directive('pip-command-description', PipCommandDescription) - app.add_directive('pip-command-options', PipCommandOptions) - app.add_directive('pip-general-options', PipGeneralOptions) - app.add_directive('pip-index-options', PipIndexOptions) + app.add_directive("pip-command-usage", PipCommandUsage) + app.add_directive("pip-command-description", PipCommandDescription) + app.add_directive("pip-command-options", PipCommandOptions) + app.add_directive("pip-general-options", PipGeneralOptions) + app.add_directive("pip-index-options", PipIndexOptions) app.add_directive( - 'pip-requirements-file-options-ref-list', PipReqFileOptionsReference + "pip-requirements-file-options-ref-list", PipReqFileOptionsReference ) + app.add_directive("pip-cli", PipCLIDirective) diff --git a/noxfile.py b/noxfile.py index 165a430d14b..a530b65ba20 100644 --- a/noxfile.py +++ b/noxfile.py @@ -149,6 +149,22 @@ def get_sphinx_build_command(kind): session.run(*get_sphinx_build_command("man")) +@nox.session(name="docs-live") +def docs_live(session): + # type: (nox.Session) -> None + session.install("-e", ".") + session.install("-r", REQUIREMENTS["docs"], "sphinx-autobuild") + + session.run( + "sphinx-autobuild", + "-d=docs/build/doctrees/livehtml", + "-b=dirhtml", + "docs/html", + "docs/build/livehtml", + *session.posargs, + ) + + @nox.session def lint(session): # type: (nox.Session) -> None diff --git a/tools/requirements/docs.txt b/tools/requirements/docs.txt index a5aae67c106..aed18b5084b 100644 --- a/tools/requirements/docs.txt +++ b/tools/requirements/docs.txt @@ -1,5 +1,7 @@ sphinx == 3.2.1 furo +myst_parser +sphinx-copybutton sphinx-inline-tabs sphinxcontrib-towncrier