core
The core module provides the essential machinery that all other pj components depend on: command execution, prerequisite checking, port management, and theme configuration. These primitives handle the mechanical work of running subprocesses, validating system state, and configuring the development environment.
Constants
A horizontal rule separator used throughout for visual sectioning in logs and output.
Software Version
get_pj_version
get_pj_version ()
Get pj version from settings.ini
Process Management
Background processes—Jupyter servers, Quarto preview, nbdev watchers—accumulate during development. We need atomic cleanup to return to a known state.
kill_processes
kill_processes (args)
Kill all running pj-related processes
The pkill -f pattern matching catches processes by command line, not just process name. This matters for Quarto, which spawns as a Deno subprocess—killing “quarto” misses the actual server; killing “quarto.js preview” hits it.
Port Allocation
Multiple Jupyter instances need distinct ports. Rather than hardcode or prompt, we scan upward from a sensible default until we find an available port.
find_free_port
find_free_port (start=64000)
Find first available port starting from given port
Starting at 64000 avoids privileged ports (<1024) and common application ports (8000-9000). The 100-port window should never exhaust unless something is catastrophically wrong.
Theme Configuration
The default nbdev documentation is light-mode only. We inject a dark theme with toggle, custom syntax highlighting, and adjusted cell output styling.
setup_dark_theme
setup_dark_theme (project_path, log_file=None, verbose=False)
Set up dark mode theme for nbdev docs
Quarto’s theming system expects a SCSS file for dark mode overrides. The key insight: cell outputs default to system colors, which are invisible on dark backgrounds. We force explicit colors for all output contexts.
Command Validation
Before running a complex workflow, verify that all required tools exist. Failing fast with installation hints beats cryptic subprocess errors halfway through.
check_cmd
check_cmd (cmd, install_hint)
Check if a command exists in PATH
shutil.which() searches $PATH reliably across platforms. Returns the full path if found, None otherwise.
Command Execution
All subprocess calls funnel through run_cmd(), which provides consistent logging, error handling, and optional verbose output with formatted boundaries.
run_cmd
run_cmd (cmd, cwd=None, check=True, capture_output=False, log_file=None, verbose=False)
Run a shell command with optional logging and pretty output
Three modes: capture (return stdout/stderr for parsing), verbose (stream with box borders), silent (log to file only). The verbose mode’s box drawing makes it clear where command output begins and ends—essential when debugging multi-step processes.
The mock Result class in verbose mode maintains API compatibility: callers always get an object with .returncode, .stdout, .stderr attributes.
Git Configuration
Extract user information from git config for populating project metadata without prompting.
get_git_config
get_git_config (key)
Get git config value
Returns None on any failure—missing git, key not set, etc. Callers provide sensible defaults when None is returned.