Rebuild Sphinx documentation on changes, with hot reloading in the browser.
Helper functions for port management, browser automation, and formatted console output. These utilities support the core functionality with common operations needed across the sphinx-autobuild system.
Find available network ports for the development server.
def find_free_port():
"""
Find and return a free port number.
Uses socket binding to discover available ports on the local machine.
The port is immediately released after discovery, so there's a small
race condition window where another process could claim it.
Returns:
- int - Available port number (typically in ephemeral range 32768-65535)
Raises:
- OSError - If no ports are available or socket operations fail
Implementation:
- Creates socket with SO_REUSEADDR option
- Binds to ('', 0) to let OS assign free port
- Returns the assigned port number
- Socket is automatically closed via context manager
"""Usage Examples:
from sphinx_autobuild.utils import find_free_port
# Get any available port
port = find_free_port()
print(f"Using port: {port}") # e.g., "Using port: 54321"
# Use in server configuration
if args.port == 0:
port = find_free_port()
else:
port = args.portAutomatically open web browsers to view documentation.
def open_browser(url_host: str, delay: float) -> None:
"""
Open browser to specified URL after delay.
Launches the system default browser in a separate thread to avoid
blocking the main application. The delay allows the server to fully
start before the browser attempts to connect.
Parameters:
- url_host: str - Host and port in format "host:port" (e.g., "127.0.0.1:8000")
- delay: float - Delay in seconds before opening browser
Returns:
- None
Side Effects:
- Creates and starts background thread for browser launching
- Thread sleeps for specified delay then opens browser
- Uses webbrowser.open() with full HTTP URL
- Thread is joined (blocks until browser launch completes)
Error Handling:
- webbrowser.open() failures are handled by webbrowser module
- Thread exceptions are not propagated to caller
"""Usage Examples:
from sphinx_autobuild.utils import open_browser
# Open browser immediately
open_browser("127.0.0.1:8000", 0)
# Open browser after 5 second delay (typical)
open_browser("localhost:8080", 5.0)
# Open browser for external access
open_browser("192.168.1.100:3000", 2.5)
# Integration with command line
if args.open_browser:
open_browser(url_host, args.delay)Formatted console messages with colors and consistent styling.
def show_message(context: str, /) -> None:
"""
Show message with colored formatting.
Displays informational messages with consistent sphinx-autobuild branding
and cyan-colored text for easy identification in console output.
Parameters:
- context: str - Message text to display
Returns:
- None
Side Effects:
- Prints to stdout with color formatting
- Uses colorama for cross-platform color support
- Format: "[sphinx-autobuild] {cyan_text}{reset}"
"""
def show_command(command: list[str] | tuple[str, ...], /) -> None:
"""
Show command with colored formatting.
Displays commands that are about to be executed with consistent formatting
and blue-colored text. Uses shlex.join() for proper shell quoting.
Parameters:
- command: list[str] | tuple[str, ...] - Command as sequence of arguments
Returns:
- None
Raises:
- AssertionError - If command is not list or tuple
Side Effects:
- Prints to stdout with color formatting
- Format: "[sphinx-autobuild] > {blue_command}{reset}"
- Properly quotes arguments with spaces or special characters
"""Usage Examples:
from sphinx_autobuild.utils import show_message, show_command
# Status messages
show_message("Starting initial build")
show_message("Waiting to detect changes...")
show_message("Server ceasing operations. Cheerio!")
# Command execution display
show_command(["python", "-m", "sphinx", "docs", "_build/html"])
show_command(["echo", "Build complete"])
show_command(["find", ".", "-name", "*.py", "-exec", "echo", "{}", ";"])
# Output examples:
# [sphinx-autobuild] Starting initial build
# [sphinx-autobuild] > python -m sphinx docs _build/html
# [sphinx-autobuild] > echo "Build complete"
# [sphinx-autobuild] > find . -name '*.py' -exec echo '{}' ';'Uses colorama for cross-platform color support:
from colorama import Fore, Style
# Internal color function
def _log(text, *, colour):
print(f"{Fore.GREEN}[sphinx-autobuild] {colour}{text}{Style.RESET_ALL}")
# Color assignments
show_message: colour=Fore.CYAN # Cyan for informational messages
show_command: colour=Fore.BLUE # Blue for command displayBrowser opening uses thread-based delay:
import threading
import time
import webbrowser
def open_browser(url_host: str, delay: float) -> None:
def _opener():
time.sleep(delay) # Blocking delay in thread
webbrowser.open(f"http://{url_host}") # System browser launch
t = threading.Thread(target=_opener)
t.start() # Start background thread
t.join() # Wait for completion (browser launch)Uses shlex for proper shell command formatting:
import shlex
def show_command(command):
assert isinstance(command, (list, tuple))
msg = f"> {shlex.join(command)}" # Proper shell quoting
_log(msg, colour=Fore.BLUE)from sphinx_autobuild.utils import show_message, show_command
from sphinx_autobuild.build import Builder
class CustomBuilder(Builder):
def __call__(self, *, changed_paths):
if changed_paths:
show_message(f"Detected changes in {len(changed_paths)} files")
show_message("Starting build process")
show_command(["python", "-m", "sphinx"] + self.sphinx_args)
# Execute build...
show_message(f"Serving on {self.uri}")from sphinx_autobuild.utils import find_free_port, open_browser, show_message
def start_server(args):
# Port selection
if args.port == 0:
port = find_free_port()
show_message(f"Using automatically selected port: {port}")
else:
port = args.port
url_host = f"{args.host}:{port}"
# Browser automation
if args.open_browser:
show_message(f"Will open browser in {args.delay} seconds")
open_browser(url_host, args.delay)
show_message(f"Starting server on {url_host}")
# Start server...from sphinx_autobuild.utils import show_command, show_message
import subprocess
def run_pre_build_commands(commands):
for command in commands:
show_message("Running pre-build command")
show_command(command)
try:
subprocess.run(command, check=True)
show_message("Pre-build command completed successfully")
except subprocess.CalledProcessError as e:
show_message(f"Pre-build command failed with exit code {e.returncode}")open command via webbrowser modulefrom sphinx_autobuild.utils import find_free_port
try:
port = find_free_port()
except OSError as e:
print(f"Could not find free port: {e}")
# Fallback to default port or exit# Browser opening failures are handled internally by webbrowser module
# No exceptions are raised to the caller
open_browser("127.0.0.1:8000", 5) # Always succeeds (may fail silently)# Colors automatically disabled in non-TTY environments
# colorama handles platform-specific color support
show_message("This message") # Colors work where supported, plain text elsewhereInstall with Tessl CLI
npx tessl i tessl/pypi-sphinx-autobuild