def METHOD_NAME(*, out_dir, temp_dir, modules):
    """Generates into out_dir; writes scratch files into temp_dir.
    As a precondition, both directories must already exist and be empty.
    If modules are provided, only generate those modules and their children.
    """
    assert len(os.listdir(temp_dir)) == 0
    assert len(os.listdir(out_dir)) == 0
    sphinx_build = "/usr/share/sphinx/scripts/python3/sphinx-build"
    if not os.path.isfile(sphinx_build):
        print("Please re-run 'sudo setup/ubuntu/install_prereqs.sh' with the "
              "'--with-doc-only' flag")
        sys.exit(1)
    # Create a hermetic copy of our input.  This helps ensure that only files
    # listed in BUILD.bazel will render onto the website.
    symlink_input(
        "drake/doc/pydrake/sphinx_input.txt", temp_dir,
        strip_prefix=["drake/doc/"])
    input_dir = join(temp_dir, "pydrake")
    # Process the command-line request for which modules to document.
    all_modules = _get_pydrake_modules()
    if not modules:
        modules_to_document = set(all_modules)
    else:
        modules_to_document = set()
        for x in modules:
            if x not in all_modules:
                print(f"error: Unknown module '{x}'")
                sys.exit(1)
            # Add the requested module and its parents.
            tokens = x.split(".")
            while tokens:
                modules_to_document.add(".".join(tokens))
                tokens.pop()
            # Add the requested module's children.
            for y in all_modules:
                if y.startswith(x + "."):
                    modules_to_document.add(y)
    # Generate tables of contents.
    for name in sorted(list(modules_to_document)):
        if name == "pydrake":
            rst_name = "index.rst"
        else:
            rst_name = name + ".rst"
        _write_module(name, join(input_dir, rst_name))
    # Run the documentation generator.
    os.environ["LANG"] = "en_US.UTF-8"
    check_call([
        sphinx_build,
        "-b", "html",  # HTML output.
        "-a", "-E",  # Don't use caching.
        "-N",  # Disable colored output.
        "-T",  # Traceback (for plugin).
        "-d", join(temp_dir, "doctrees"),
        input_dir,
        out_dir,
    ])
    # Tidy up.
    perl_cleanup_html_output(out_dir=out_dir)
    # Check for regressions.
    _sanity_check_output(out_dir=out_dir)
    # The filename to suggest as the starting point for preview; in this case,
    # it's an empty filename (i.e., the index page).
    return [""]