Repository: jazzband/pip-tools (python)

Issue:
Generate API spec page
We should start doing that, then. I usually integrate `sphinxcontrib-apidoc` for automatic generation like this: https://github.com/cherrypy/cheroot/commit/cb9d3f46aa755d63e85d539a2efb7d1fa8f53935. Later on, I remembered to mark the ToC section as **private**: https://cheroot.cherrypy.dev/en/latest/pkg/modules/.

_Originally posted by @webknjaz in https://github.com/jazzband/pip-tools/pull/1981#discussion_r1353607650_

I'll have a look at this, thanks for the hints!
            

Pull request:
Add private API documentation
<!--- Describe the changes here. --->

Closes #1999. Thanks for providing the example, @webknjaz!

##### Contributor checklist

- [ ] Included tests for the changes.
- [ ] PR title is short, clear, and ready to be included in the user-facing changelog.

##### Maintainer checklist

- [x] Verified one of these labels is present: `backwards incompatible`, `feature`, `enhancement`, `deprecation`, `bug`, `dependency`, `docs` or `skip-changelog` as they determine changelog listing.
- [ ] Assign the PR to an existing or new milestone for the target version (following [Semantic Versioning](https://blog.versioneye.com/2014/01/16/semantic-versioning/)).


Patch:
diff --git a/docs/conf.py b/docs/conf.py
index 7e88659..0aa707b 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -36,7 +36,14 @@ logger.info(bold("%s release: %s"), project, release)
 # Add any Sphinx extension module names here, as strings. They can be
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
-extensions = ["myst_parser", "sphinxcontrib.programoutput"]
+extensions = [
+    # Stdlib extensions:
+    "sphinx.ext.intersphinx",
+    # Third-party extensions:
+    "myst_parser",
+    "sphinxcontrib.apidoc",
+    "sphinxcontrib.programoutput",
+]
 
 
 # -- Options for HTML output -------------------------------------------------
@@ -48,6 +55,14 @@ html_theme = "furo"
 html_title = f"<nobr>{project}</nobr> documentation v{release}"
 
 
+# -- Options for intersphinx ----------------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html#configuration
+
+intersphinx_mapping = {
+    "python": ("https://docs.python.org/3", None),
+}
+
+
 # -------------------------------------------------------------------------
 default_role = "any"
 nitpicky = True
@@ -57,4 +72,30 @@ linkcheck_ignore = [
     r"^https://img.shields.io/matrix",
 ]
 
+nitpick_ignore_regex = [
+    ("py:class", "pip.*"),
+    ("py:class", "pathlib.*"),
+    ("py:class", "click.*"),
+    ("py:class", "build.*"),
+    ("py:class", "optparse.*"),
+    ("py:class", "_ImportLibDist"),
+    ("py:class", "PackageMetadata"),
+    ("py:class", "importlib.*"),
+    ("py:class", "IndexContent"),
+    ("py:exc", "click.*"),
+]
+
 suppress_warnings = ["myst.xref_missing"]
+
+# -- Apidoc options -------------------------------------------------------
+
+apidoc_excluded_paths: list[str] = []
+apidoc_extra_args = [
+    "--implicit-namespaces",
+    "--private",  # include “_private” modules
+]
+apidoc_module_first = False
+apidoc_module_dir = "../piptools"
+apidoc_output_dir = "pkg"
+apidoc_separate_modules = True
+apidoc_toc_file = None
diff --git a/docs/index.md b/docs/index.md
index f9ab197..e3a99fe 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -13,3 +13,10 @@ cli/index
 contributing
 changelog
 ```
+
+```{toctree}
+:hidden:
+:caption: Private API reference
+
+pkg/modules
+```
diff --git a/docs/pkg/.gitignore b/docs/pkg/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/docs/pkg/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/docs/requirements.in b/docs/requirements.in
index fdee133..b772fde 100644
--- a/docs/requirements.in
+++ b/docs/requirements.in
@@ -2,4 +2,5 @@ furo
 myst-parser
 setuptools-scm
 sphinx
+sphinxcontrib-apidoc
 sphinxcontrib-programoutput
diff --git a/docs/requirements.txt b/docs/requirements.txt
index 8349267..645562f 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -2,7 +2,7 @@
 # This file is autogenerated by pip-compile with Python 3.11
 # by the following command:
 #
-#    pip-compile --allow-unsafe --strip-extras docs/requirements.in
+#    pip-compile --allow-unsafe --strip-extras requirements.in
 #
 alabaster==0.7.13
     # via sphinx
@@ -44,6 +44,8 @@ packaging==23.1
     # via
     #   setuptools-scm
     #   sphinx
+pbr==6.0.0
+    # via sphinxcontrib-apidoc
 pygments==2.16.1
     # via
     #   furo
@@ -64,6 +66,7 @@ sphinx==7.2.2
     #   furo
     #   myst-parser
     #   sphinx-basic-ng
+    #   sphinxcontrib-apidoc
     #   sphinxcontrib-applehelp
     #   sphinxcontrib-devhelp
     #   sphinxcontrib-htmlhelp
@@ -72,6 +75,8 @@ sphinx==7.2.2
     #   sphinxcontrib-serializinghtml
 sphinx-basic-ng==1.0.0b2
     # via furo
+sphinxcontrib-apidoc==0.5.0
+    # via -r requirements.in
 sphinxcontrib-applehelp==1.0.7
     # via sphinx
 sphinxcontrib-devhelp==1.0.5
diff --git a/piptools/_compat/pip_compat.py b/piptools/_compat/pip_compat.py
index d956ab2..31c45f9 100644
--- a/piptools/_compat/pip_compat.py
+++ b/piptools/_compat/pip_compat.py
@@ -50,9 +50,12 @@ class Distribution:
 
     @classmethod
     def _from_importlib(cls, dist: _ImportLibDist) -> Distribution:
-        """Mimics pkg_resources.Distribution.requires for the case of no
-        extras. This doesn't fulfill that API's `extras` parameter but
-        satisfies the needs of pip-tools."""
+        """Mimic pkg_resources.Distribution.requires for the case of no
+        extras.
+
+        This doesn't fulfill that API's ``extras`` parameter but
+        satisfies the needs of pip-tools.
+        """
         reqs = (Requirement.parse(req) for req in (dist._dist.requires or ()))
         requires = [
             req
@@ -63,6 +66,8 @@ class Distribution:
 
 
 class FileLink(Link):  # type: ignore[misc]
+    """Wrapper for ``pip``'s ``Link`` class."""
+
     _url: str
 
     @property
diff --git a/piptools/cache.py b/piptools/cache.py
index 3570c43..91e1fa4 100644
--- a/piptools/cache.py
+++ b/piptools/cache.py
@@ -21,6 +21,8 @@ _PEP425_PY_TAGS = {"cpython": "cp", "pypy": "pp", "ironpython": "ip", "jython":
 
 def _implementation_name() -> str:
     """
+    Get Python implementation and version.
+
     Similar to PEP 425, however the minor version is separated from the major to
     differentiate "3.10" and "31.0".
     """
@@ -57,7 +59,8 @@ def read_cache_file(cache_file_path: str) -> CacheDict:
 
 class DependencyCache:
     """
-    Creates a new persistent dependency cache for the current Python version.
+    Create new persistent dependency cache for the current Python version.
+
     The cache file is written to the appropriate user cache dir for the
     current platform, i.e.
 
@@ -89,7 +92,9 @@ class DependencyCache:
 
     def as_cache_key(self, ireq: InstallRequirement) -> CacheKey:
         """
-        Given a requirement, return its cache key. This behavior is a little weird
+        Given a requirement, return its cache key.
+
+        This behavior is a little weird
         in order to allow backwards compatibility with cache files. For a requirement
         without extras, this will return, for example:
 
@@ -108,7 +113,7 @@ class DependencyCache:
         return name, f"{version}{extras_string}"
 
     def write_cache(self) -> None:
-        """Writes the cache to disk as JSON."""
+        """Write the cache to disk as JSON."""
         doc = {"__format__": 1, "dependencies": self._cache}
         with open(self._cache_file, "w", encoding="utf-8") as f:
             json.dump(doc, f, sort_keys=True)
@@ -135,7 +140,7 @@ class DependencyCache:
         self, ireqs: Iterable[InstallRequirement]
     ) -> dict[str, set[str]]:
         """
-        Returns a lookup table of reverse dependencies for all the given ireqs.
+        Return a lookup table of reverse dependencies for all the given ireqs.
 
         Since this is all static, it only works if the dependency cache
         contains the complete data, otherwise you end up with a partial view.
@@ -149,7 +154,7 @@ class DependencyCache:
         self, cache_keys: Iterable[tuple[str, str]]
     ) -> dict[str, set[str]]:
         """
-        Returns a lookup table of reverse dependencies for all the given cache keys.
+        Return a lookup table of reverse dependencies for all the given cache keys.
 
         Example input:
 
diff --git a/piptools/repositories/local.py b/piptools/repositories/local.py
index 76cbea8..94b6b74 100644
--- a/piptools/repositories/local.py
+++ b/piptools/repositories/local.py
@@ -21,7 +21,7 @@ def ireq_satisfied_by_existing_pin(
     ireq: InstallRequirement, existing_pin: InstallationCandidate
 ) -> bool:
     """
-    Return True if the given InstallationRequirement is satisfied by the
+    Return :py:data:`True` if the given ``InstallRequirement`` is satisfied by the
     previously encountered version pin.
     """
     version = next(iter(existing_pin.req.specifier)).version
diff --git a/piptools/resolver.py b/piptools/resolver.py
index b6107dc..f784ffe 100644
--- a/piptools/resolver.py
+++ b/piptools/resolver.py
@@ -152,16 +152,18 @@ class BaseResolver(metaclass=ABCMeta):
 
     @abstractmethod
     def resolve(self, max_rounds: int) -> set[InstallRequirement]:
-        """
+        r"""
         Find concrete package versions for all the given InstallRequirements
-        and their recursive dependencies and return a set of pinned
-        ``InstallRequirement``'s.
+        and their recursive dependencies.
+        :returns: a set of pinned ``InstallRequirement``\ s.
         """
 
     def resolve_hashes(
         self, ireqs: set[InstallRequirement]
     ) -> dict[InstallRequirement, set[str]]:
-        """Find acceptable hashes for all of the given ``InstallRequirement``s."""
+        r"""
+        Find acceptable hashes for all of the given ``InstallRequirement``\ s.
+        """
         log.debug("")
         log.debug("Generating hashes:")
         with self.repository.allow_all_wheels(), log.indentation():
@@ -172,8 +174,8 @@ class BaseResolver(metaclass=ABCMeta):
         ireqs: set[InstallRequirement],
         unsafe_packages: Container[str],
     ) -> None:
-        """
-        Remove from a given set of ``InstallRequirement``'s unsafe constraints.
+        r"""
+        Remove from a given set of ``InstallRequirement``\ s unsafe constraints.
         """
         for req in ireqs.copy():
             if req.name in unsafe_packages:
@@ -182,6 +184,10 @@ class BaseResolver(metaclass=ABCMeta):
 
 
 class LegacyResolver(BaseResolver):
+    """
+    Wrapper for the (deprecated) legacy dependency resolver.
+    """
+
     def __init__(
         self,
         constraints: Iterable[InstallRequirement],
@@ -193,10 +199,24 @@ class LegacyResolver(BaseResolver):
         allow_unsafe: bool = False,
         unsafe_packages: set[str] | None = None,
     ) -> None:
-        """
-        This class resolves a given set of constraints (a collection of
-        InstallRequirement objects) by consulting the given Repository and the
-        DependencyCache.
+        """Initialize LegacyResolver.
+
+        :param constraints: the constraints given
+        :type constraints: Iterable[InstallRequirement]
+        :param existing_constraints: constraints already present
+        :param repository: the repository to get the constraints from
+        :type repository: BaseRepository
+        :param cache: the cache to be used
+        :param prereleases: whether prereleases should be taken into account when resolving
+            (default is :py:data:`False`)
+        :param clear_caches: whether to clear repository and dependency caches before resolving
+            (default is :py:data:`False`)
+        :param allow_unsafe: whether unsafe packages should be allowed in the resulting requirements
+            (default is :py:data:`False`)
+        :param unsafe_packages: packages to be considered as unsafe
+            (default is :py:data:`None`)
+        :type unsafe_packages: set[str]
+        :raises: ``PipToolsError`` if the legacy resolver is not enabled
         """
         self.our_constraints = set(constraints)
         self.their_constraints: set[InstallRequirement] = set()
@@ -224,14 +244,16 @@ class LegacyResolver(BaseResolver):
         )
 
     def resolve(self, max_rounds: int = 10) -> set[InstallRequirement]:
-        """
-        Find concrete package versions for all the given InstallRequirements
+        r"""
+        Find concrete package versions for all the given ``InstallRequirement``\ s
         and their recursive dependencies and return a set of pinned
-        ``InstallRequirement``'s.
+        ``InstallRequirement``\ s.
 
         Resolves constraints one round at a time, until they don't change
-        anymore.  Protects against infinite loops by breaking out after a max
-        number rounds.
+        anymore.
+
+        :param max_rounds: break out of resolution process after the given number of rounds
+            to prevent infinite loops (default is 10)
         """
         if self.clear_caches:
             self.dependency_cache.clear()
@@ -277,8 +299,9 @@ class LegacyResolver(BaseResolver):
         self, constraints: Iterable[InstallRequirement]
     ) -> Iterator[InstallRequirement]:
         """
-        Groups constraints (remember, InstallRequirements!) by their key name,
-        and combining their SpecifierSets into a single InstallRequirement per
+        Group constraints (remember, InstallRequirements!) by their key name.
+
+        Then combine their SpecifierSets into a single InstallRequirement per
         package.  For example, given the following constraints:
 
             Django<1.9,>=1.4.2
@@ -311,14 +334,16 @@ class LegacyResolver(BaseResolver):
 
     def _resolve_one_round(self) -> tuple[bool, set[InstallRequirement]]:
         """
-        Resolves one level of the current constraints, by finding the best
-        match for each package in the repository and adding all requirements
-        for those best package versions.  Some of these constraints may be new
+        Resolve one level of the current constraints.
+
+        This is achieved by finding the best match for each package
+        in the repository and adding all requirements for those best
+        package versions.  Some of these constraints may be new
         or updated.
 
-        Returns whether new constraints appeared in this round.  If no
-        constraints were added or changed, this indicates a stable
-        configuration.
+        :returns: whether new constraints appeared in this round.  If no
+            constraints were added or changed, this indicates a stable
+            configuration.
         """
         # Sort this list for readability of terminal output
         constraints = sorted(self.constraints, key=key_from_ireq)
@@ -371,9 +396,10 @@ class LegacyResolver(BaseResolver):
 
     def get_best_match(self, ireq: InstallRequirement) -> InstallRequirement:
         """
-        Returns a (pinned or editable) InstallRequirement, indicating the best
-        match to use for the given InstallRequirement (in the form of an
-        InstallRequirement).
+        Return a (pinned or editable) InstallRequirement.
+
+        This indicates the best match to use for the given
+        InstallRequirement (in the form of an InstallRequirement).
 
         Example:
         Given the constraint Flask>=0.10, may return Flask==0.10.1 at
@@ -416,6 +442,8 @@ class LegacyResolver(BaseResolver):
         self, ireq: InstallRequirement
     ) -> Iterator[InstallRequirement]:
         """
+        Emit all secondary dependencies for an ireq.
+
         Given a pinned, url, or editable InstallRequirement, collects all the
         secondary dependencies for them, either by looking them up in a local
         cache, or by reaching out to the repository.
@@ -479,7 +507,7 @@ class LegacyResolver(BaseResolver):
 
 
 class BacktrackingResolver(BaseResolver):
-    """A wrapper for backtracking resolver."""
+    """A wrapper for the backtracking (or 2020) resolver."""
 
     def __init__(
         self,
@@ -521,10 +549,13 @@ class BacktrackingResolver(BaseResolver):
         )
 
     def resolve(self, max_rounds: int = 10) -> set[InstallRequirement]:
-        """
+        r"""
+        Resolve given ireqs.
+
         Find concrete package versions for all the given InstallRequirements
-        and their recursive dependencies and return a set of pinned
-        ``InstallRequirement``'s.
+        and their recursive dependencies.
+
+        :returns: A set of pinned ``InstallRequirement``\ s.
         """
         with update_env_context_manager(
             PIP_EXISTS_ACTION="i"
@@ -629,8 +660,11 @@ class BacktrackingResolver(BaseResolver):
         compatible_existing_constraints: dict[str, InstallRequirement],
     ) -> bool:
         """
-        Return true on successful resolution, otherwise remove problematic
-        requirements from existing constraints and return false.
+        Resolve dependencies based on resolvelib ``Resolver``.
+
+        :returns: :py:data:`True` on successful resolution, otherwise removes
+            problematic requirements from existing constraints and
+            returns :py:data:`False`.
         """
         try:
             resolver.resolve(
diff --git a/piptools/scripts/compile.py b/piptools/scripts/compile.py
index 2b4522e..7c53435 100755
--- a/piptools/scripts/compile.py
+++ b/piptools/scripts/compile.py
@@ -49,6 +49,7 @@ def _determine_linesep(
 ) -> str:
     """
     Determine and return linesep string for OutputWriter to use.
+
     Valid strategies: "LF", "CRLF", "native", "preserve"
     When preserving, files are checked in order for existing newlines.
     """
@@ -169,7 +170,9 @@ def cli(
     only_build_deps: bool,
 ) -> None:
     """
-    Compiles requirements.txt from requirements.in, pyproject.toml, setup.cfg,
+    Compile requirements.txt from source files.
+
+    Valid sources are requirements.in, pyproject.toml, setup.cfg,
     or setup.py specs.
     """
     if color is not None:
diff --git a/piptools/subprocess_utils.py b/piptools/subprocess_utils.py
index 49458a2..8c9faec 100644
--- a/piptools/subprocess_utils.py
+++ b/piptools/subprocess_utils.py
@@ -7,7 +7,7 @@ import subprocess  # nosec
 
 def run_python_snippet(python_executable: str, code_to_run: str) -> str:
     """
-    Executes python code by calling python_executable with '-c' option.
+    Execute Python code by calling ``python_executable`` with '-c' option.
     """
     py_exec_cmd = python_executable, "-c", code_to_run
 
diff --git a/piptools/sync.py b/piptools/sync.py
index c1d690a..5408fd8 100644
--- a/piptools/sync.py
+++ b/piptools/sync.py
@@ -43,13 +43,15 @@ PACKAGES_TO_IGNORE = [
 def dependency_tree(
     installed_keys: Mapping[str, Distribution], root_key: str
 ) -> set[str]:
-    """
-    Calculate the dependency tree for the package `root_key` and return
-    a collection of all its dependencies.  Uses a DFS traversal algorithm.
+    """Calculate the dependency tree for a package.
+
+    Return a collection of all of the package's dependencies.
+    Uses a DFS traversal algorithm.
 
-    `installed_keys` should be a {key: requirement} mapping, e.g.
-        {'django': from_line('django==1.8')}
-    `root_key` should be the key to return the dependency tree for.
+    ``installed_keys`` should be a {key: requirement} mapping, e.g.
+    {'django': from_line('django==1.8')}
+    :param root_key: the key to return the dependency tree for
+    :type root_key: str
     """
     dependencies = set()
     queue: Deque[Distribution] = collections.deque()
@@ -78,9 +80,9 @@ def dependency_tree(
 
 
 def get_dists_to_ignore(installed: Iterable[Distribution]) -> list[str]:
-    """
-    Returns a collection of package names to ignore when performing pip-sync,
-    based on the currently installed environment.  For example, when pip-tools
+    """Return a collection of package names to ignore by ``pip-sync``.
+
+    Based on the currently installed environment.  For example, when pip-tools
     is installed in the local environment, it should be ignored, including all
     of its dependencies (e.g. click).  When pip-tools is not installed
     locally, click should also be installed/uninstalled depending on the given
@@ -122,11 +124,11 @@ def merge(
 
 
 def diff_key_from_ireq(ireq: InstallRequirement) -> str:
-    """
-    Calculate a key for comparing a compiled requirement with installed modules.
+    """Calculate key for comparing a compiled requirement with installed modules.
+
     For URL requirements, only provide a useful key if the url includes
     a hash, e.g. #sha1=..., in any of the supported hash algorithms.
-    Otherwise return ireq.link so the key will not match and the package will
+    Otherwise return ``ireq.link`` so the key will not match and the package will
     reinstall. Reinstall is necessary to ensure that packages will reinstall
     if the contents at the URL have changed but the version has not.
     """
@@ -159,9 +161,10 @@ def diff(
     compiled_requirements: Iterable[InstallRequirement],
     installed_dists: Iterable[Distribution],
 ) -> tuple[set[InstallRequirement], set[str]]:
-    """
-    Calculate which packages should be installed or uninstalled, given a set
-    of compiled requirements and a list of currently installed modules.
+    """Calculate which packages should be installed or uninstalled.
+
+    Compared are the compiled requirements and a list of currently
+    installed modules.
     """
     requirements_lut = {diff_key_from_ireq(r): r for r in compiled_requirements}
 
@@ -195,9 +198,7 @@ def sync(
     ask: bool = False,
     python_executable: str | None = None,
 ) -> int:
-    """
-    Install and uninstalls the given sets of modules.
-    """
+    """Install and uninstall the given sets of modules."""
     exit_code = 0
 
     python_executable = python_executable or sys.executable
diff --git a/piptools/utils.py b/piptools/utils.py
index 8d04f7a..b501fac 100644
--- a/piptools/utils.py
+++ b/piptools/utils.py
@@ -122,8 +122,9 @@ def make_install_requirement(
 
 def is_url_requirement(ireq: InstallRequirement) -> bool:
     """
-    Return True if requirement was specified as a path or URL.
-    ireq.original_link will have been set by InstallRequirement.__init__
+    Return :py:data:`True` if requirement was specified as a path or URL.
+
+    ``ireq.original_link`` will have been set by ``InstallRequirement.__init__``
     """
     return bool(ireq.original_link)
 
@@ -135,7 +136,7 @@ def format_requirement(
 ) -> str:
     """
     Generic formatter for pretty printing InstallRequirements to the terminal
-    in a less verbose way than using its `__str__` method.
+    in a less verbose way than using its ``__str__`` method.
     """
     if ireq.editable:
         line = f"-e {ireq.link.url}"
@@ -160,7 +161,8 @@ def format_requirement(
 
 def _build_direct_reference_best_efforts(ireq: InstallRequirement) -> str:
     """
-    Returns a string of a direct reference URI, whenever possible.
+    Return a string of a direct reference URI, whenever possible.
+
     See https://www.python.org/dev/peps/pep-0508/
     """
     # If the requirement has no name then we cannot build a direct reference.
@@ -207,7 +209,7 @@ def format_specifier(ireq: InstallRequirement) -> str:
 
 def is_pinned_requirement(ireq: InstallRequirement) -> bool:
     """
-    Returns whether an InstallRequirement is a "pinned" requirement.
+    Return whether an InstallRequirement is a "pinned" requirement.
 
     An InstallRequirement is considered pinned if:
 
@@ -234,7 +236,7 @@ def is_pinned_requirement(ireq: InstallRequirement) -> bool:
 
 def as_tuple(ireq: InstallRequirement) -> tuple[str, str, tuple[str, ...]]:
     """
-    Pulls out the (name: str, version:str, extras:(str)) tuple from
+    Pull out the (name: str, version:str, extras:(str)) tuple from
     the pinned InstallRequirement.
     """
     if not is_pinned_requirement(ireq):
@@ -254,9 +256,7 @@ def flat_map(
 
 
 def lookup_table_from_tuples(values: Iterable[tuple[_KT, _VT]]) -> dict[_KT, set[_VT]]:
-    """
-    Builds a dict-based lookup table (index) elegantly.
-    """
+    """Build a dict-based lookup table (index) elegantly."""
     lut: dict[_KT, set[_VT]] = collections.defaultdict(set)
     for k, v in values:
         lut[k].add(v)
@@ -266,14 +266,13 @@ def lookup_table_from_tuples(values: Iterable[tuple[_KT, _VT]]) -> dict[_KT, set
 def lookup_table(
     values: Iterable[_VT], key: Callable[[_VT], _KT]
 ) -> dict[_KT, set[_VT]]:
-    """
-    Builds a dict-based lookup table (index) elegantly.
-    """
+    """Build a dict-based lookup table (index) elegantly."""
     return lookup_table_from_tuples((key(v), v) for v in values)
 
 
 def dedup(iterable: Iterable[_T]) -> Iterable[_T]:
-    """Deduplicate an iterable object like iter(set(iterable)) but
+    """
+    Deduplicate an iterable object like ``iter(set(iterable))`` but
     order-preserved.
     """
     return iter(dict.fromkeys(iterable))
@@ -345,7 +344,7 @@ def get_hashes_from_ireq(ireq: InstallRequirement) -> set[str]:
 
 def get_compile_command(click_ctx: click.Context) -> str:
     """
-    Returns a normalized compile command depending on cli context.
+    Return a normalized compile command depending on cli context.
 
     The command will be normalized by:
         - expanding options short to long
@@ -444,7 +443,7 @@ def get_compile_command(click_ctx: click.Context) -> str:
 
 def get_required_pip_specification() -> SpecifierSet:
     """
-    Returns pip version specifier requested by current pip-tools installation.
+    Return pip version specifier requested by current pip-tools installation.
     """
     project_dist = get_distribution("pip-tools")
     requirement = next(
@@ -457,9 +456,7 @@ def get_required_pip_specification() -> SpecifierSet:
 
 
 def get_pip_version_for_python_executable(python_executable: str) -> Version:
-    """
-    Returns pip version for the given python executable.
-    """
+    """Return pip version for the given python executable."""
     str_version = run_python_snippet(
         python_executable, "import pip;print(pip.__version__)"
     )
@@ -468,7 +465,7 @@ def get_pip_version_for_python_executable(python_executable: str) -> Version:
 
 def get_sys_path_for_python_executable(python_executable: str) -> list[str]:
     """
-    Returns sys.path list for the given python executable.
+    Return sys.path list for the given python executable.
     """
     result = run_python_snippet(
         python_executable, "import sys;import json;print(json.dumps(sys.path))"
@@ -543,11 +540,11 @@ def override_defaults_from_config_file(
     ctx: click.Context, param: click.Parameter, value: str | None
 ) -> Path | None:
     """
-    Overrides ``click.Command`` defaults based on specified or discovered config
+    Override ``click.Command`` defaults based on specified or discovered config
     file, returning the ``pathlib.Path`` of that config file if specified or
     discovered.
 
-    ``None`` is returned if no such file is found.
+    :returns: :py:data:`None` if no such file is found, else returns the path.
 
     ``pip-tools`` will use the first config file found, searching in this order:
     an explicitly given config file, a ``.pip-tools.toml``, a ``pyproject.toml``
@@ -640,7 +637,7 @@ def _validate_config(
 
 def select_config_file(src_files: tuple[str, ...]) -> Path | None:
     """
-    Returns the config file to use for defaults given ``src_files`` provided.
+    Return the config file to use for defaults given ``src_files`` provided.
     """
     # NOTE: If no src_files were specified, consider the current directory the
     # NOTE: only config file lookup candidate. This usually happens when a


Test patch:
diff --git a/tests/test_cli_compile.py b/tests/test_cli_compile.py
index ad66dc3..2c939ab 100644
--- a/tests/test_cli_compile.py
+++ b/tests/test_cli_compile.py
@@ -456,7 +456,7 @@ def test_run_as_module_compile():
 
     # Should have run pip-compile successfully.
     assert result.stdout.startswith(b"Usage:")
-    assert b"Compiles requirements.txt from requirements.in" in result.stdout
+    assert b"Compile requirements.txt from source files" in result.stdout
 
 
 def test_editable_package(pip_conf, runner):