0
# Utility Functions
1
2
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.
3
4
## Capabilities
5
6
### Port Management
7
8
Find available network ports for the development server.
9
10
```python { .api }
11
def find_free_port():
12
"""
13
Find and return a free port number.
14
15
Uses socket binding to discover available ports on the local machine.
16
The port is immediately released after discovery, so there's a small
17
race condition window where another process could claim it.
18
19
Returns:
20
- int - Available port number (typically in ephemeral range 32768-65535)
21
22
Raises:
23
- OSError - If no ports are available or socket operations fail
24
25
Implementation:
26
- Creates socket with SO_REUSEADDR option
27
- Binds to ('', 0) to let OS assign free port
28
- Returns the assigned port number
29
- Socket is automatically closed via context manager
30
"""
31
```
32
33
**Usage Examples:**
34
35
```python
36
from sphinx_autobuild.utils import find_free_port
37
38
# Get any available port
39
port = find_free_port()
40
print(f"Using port: {port}") # e.g., "Using port: 54321"
41
42
# Use in server configuration
43
if args.port == 0:
44
port = find_free_port()
45
else:
46
port = args.port
47
```
48
49
### Browser Automation
50
51
Automatically open web browsers to view documentation.
52
53
```python { .api }
54
def open_browser(url_host: str, delay: float) -> None:
55
"""
56
Open browser to specified URL after delay.
57
58
Launches the system default browser in a separate thread to avoid
59
blocking the main application. The delay allows the server to fully
60
start before the browser attempts to connect.
61
62
Parameters:
63
- url_host: str - Host and port in format "host:port" (e.g., "127.0.0.1:8000")
64
- delay: float - Delay in seconds before opening browser
65
66
Returns:
67
- None
68
69
Side Effects:
70
- Creates and starts background thread for browser launching
71
- Thread sleeps for specified delay then opens browser
72
- Uses webbrowser.open() with full HTTP URL
73
- Thread is joined (blocks until browser launch completes)
74
75
Error Handling:
76
- webbrowser.open() failures are handled by webbrowser module
77
- Thread exceptions are not propagated to caller
78
"""
79
```
80
81
**Usage Examples:**
82
83
```python
84
from sphinx_autobuild.utils import open_browser
85
86
# Open browser immediately
87
open_browser("127.0.0.1:8000", 0)
88
89
# Open browser after 5 second delay (typical)
90
open_browser("localhost:8080", 5.0)
91
92
# Open browser for external access
93
open_browser("192.168.1.100:3000", 2.5)
94
95
# Integration with command line
96
if args.open_browser:
97
open_browser(url_host, args.delay)
98
```
99
100
### Console Output
101
102
Formatted console messages with colors and consistent styling.
103
104
```python { .api }
105
def show_message(context: str, /) -> None:
106
"""
107
Show message with colored formatting.
108
109
Displays informational messages with consistent sphinx-autobuild branding
110
and cyan-colored text for easy identification in console output.
111
112
Parameters:
113
- context: str - Message text to display
114
115
Returns:
116
- None
117
118
Side Effects:
119
- Prints to stdout with color formatting
120
- Uses colorama for cross-platform color support
121
- Format: "[sphinx-autobuild] {cyan_text}{reset}"
122
"""
123
124
def show_command(command: list[str] | tuple[str, ...], /) -> None:
125
"""
126
Show command with colored formatting.
127
128
Displays commands that are about to be executed with consistent formatting
129
and blue-colored text. Uses shlex.join() for proper shell quoting.
130
131
Parameters:
132
- command: list[str] | tuple[str, ...] - Command as sequence of arguments
133
134
Returns:
135
- None
136
137
Raises:
138
- AssertionError - If command is not list or tuple
139
140
Side Effects:
141
- Prints to stdout with color formatting
142
- Format: "[sphinx-autobuild] > {blue_command}{reset}"
143
- Properly quotes arguments with spaces or special characters
144
"""
145
```
146
147
**Usage Examples:**
148
149
```python
150
from sphinx_autobuild.utils import show_message, show_command
151
152
# Status messages
153
show_message("Starting initial build")
154
show_message("Waiting to detect changes...")
155
show_message("Server ceasing operations. Cheerio!")
156
157
# Command execution display
158
show_command(["python", "-m", "sphinx", "docs", "_build/html"])
159
show_command(["echo", "Build complete"])
160
show_command(["find", ".", "-name", "*.py", "-exec", "echo", "{}", ";"])
161
162
# Output examples:
163
# [sphinx-autobuild] Starting initial build
164
# [sphinx-autobuild] > python -m sphinx docs _build/html
165
# [sphinx-autobuild] > echo "Build complete"
166
# [sphinx-autobuild] > find . -name '*.py' -exec echo '{}' ';'
167
```
168
169
## Internal Implementation Details
170
171
### Color Management
172
173
Uses colorama for cross-platform color support:
174
175
```python
176
from colorama import Fore, Style
177
178
# Internal color function
179
def _log(text, *, colour):
180
print(f"{Fore.GREEN}[sphinx-autobuild] {colour}{text}{Style.RESET_ALL}")
181
182
# Color assignments
183
show_message: colour=Fore.CYAN # Cyan for informational messages
184
show_command: colour=Fore.BLUE # Blue for command display
185
```
186
187
### Thread Management
188
189
Browser opening uses thread-based delay:
190
191
```python
192
import threading
193
import time
194
import webbrowser
195
196
def open_browser(url_host: str, delay: float) -> None:
197
def _opener():
198
time.sleep(delay) # Blocking delay in thread
199
webbrowser.open(f"http://{url_host}") # System browser launch
200
201
t = threading.Thread(target=_opener)
202
t.start() # Start background thread
203
t.join() # Wait for completion (browser launch)
204
```
205
206
### Command Formatting
207
208
Uses shlex for proper shell command formatting:
209
210
```python
211
import shlex
212
213
def show_command(command):
214
assert isinstance(command, (list, tuple))
215
msg = f"> {shlex.join(command)}" # Proper shell quoting
216
_log(msg, colour=Fore.BLUE)
217
```
218
219
## Integration Examples
220
221
### With Build System
222
223
```python
224
from sphinx_autobuild.utils import show_message, show_command
225
from sphinx_autobuild.build import Builder
226
227
class CustomBuilder(Builder):
228
def __call__(self, *, changed_paths):
229
if changed_paths:
230
show_message(f"Detected changes in {len(changed_paths)} files")
231
232
show_message("Starting build process")
233
show_command(["python", "-m", "sphinx"] + self.sphinx_args)
234
235
# Execute build...
236
237
show_message(f"Serving on {self.uri}")
238
```
239
240
### With Server Startup
241
242
```python
243
from sphinx_autobuild.utils import find_free_port, open_browser, show_message
244
245
def start_server(args):
246
# Port selection
247
if args.port == 0:
248
port = find_free_port()
249
show_message(f"Using automatically selected port: {port}")
250
else:
251
port = args.port
252
253
url_host = f"{args.host}:{port}"
254
255
# Browser automation
256
if args.open_browser:
257
show_message(f"Will open browser in {args.delay} seconds")
258
open_browser(url_host, args.delay)
259
260
show_message(f"Starting server on {url_host}")
261
# Start server...
262
```
263
264
### With Command Execution
265
266
```python
267
from sphinx_autobuild.utils import show_command, show_message
268
import subprocess
269
270
def run_pre_build_commands(commands):
271
for command in commands:
272
show_message("Running pre-build command")
273
show_command(command)
274
275
try:
276
subprocess.run(command, check=True)
277
show_message("Pre-build command completed successfully")
278
except subprocess.CalledProcessError as e:
279
show_message(f"Pre-build command failed with exit code {e.returncode}")
280
```
281
282
## Platform Compatibility
283
284
### Color Support
285
286
- **Windows**: colorama automatically initializes Windows console color support
287
- **macOS/Linux**: Native ANSI color sequence support
288
- **CI/CD**: Colors automatically disabled in non-TTY environments
289
290
### Browser Opening
291
292
- **Windows**: Uses default application associations
293
- **macOS**: Uses `open` command via webbrowser module
294
- **Linux**: Uses desktop environment's default browser (xdg-open, etc.)
295
296
### Port Discovery
297
298
- **All Platforms**: Uses standard socket operations
299
- **IPv4**: Binds to all interfaces ("") for maximum compatibility
300
- **Port Ranges**: OS assigns from available ephemeral port range
301
302
## Error Scenarios
303
304
### Port Discovery Failures
305
306
```python
307
from sphinx_autobuild.utils import find_free_port
308
309
try:
310
port = find_free_port()
311
except OSError as e:
312
print(f"Could not find free port: {e}")
313
# Fallback to default port or exit
314
```
315
316
### Browser Launch Failures
317
318
```python
319
# Browser opening failures are handled internally by webbrowser module
320
# No exceptions are raised to the caller
321
open_browser("127.0.0.1:8000", 5) # Always succeeds (may fail silently)
322
```
323
324
### Color Display Issues
325
326
```python
327
# Colors automatically disabled in non-TTY environments
328
# colorama handles platform-specific color support
329
show_message("This message") # Colors work where supported, plain text elsewhere
330
```