2025-12-17 14:17:46 -08:00
#!/usr/bin/env python3
""" scripts/setup.py
Unified project setup helper ( Python - only ) .
This script installs Python dependencies from ` requirements . txt ` and then
downloads Playwright browser binaries by running ` python - m playwright install ` .
2025-12-17 17:42:46 -08:00
By default this script installs * * Chromium * * only to conserve space ; pass
` - - browsers all ` to install all supported engines ( chromium , firefox , webkit ) .
2025-12-17 14:17:46 -08:00
Usage :
python . / scripts / setup . py # install deps and playwright browsers
python . / scripts / setup . py - - skip - deps
python . / scripts / setup . py - - playwright - only
Optional flags :
- - skip - deps Skip ` pip install - r requirements . txt ` step
- - no - playwright Skip running ` python - m playwright install ` ( still installs deps )
- - playwright - only Install only Playwright browsers ( installs playwright package if missing )
2025-12-17 17:42:46 -08:00
- - browsers Comma - separated list of Playwright browsers to install ( default : chromium )
- - install - editable Install the project in editable mode ( pip install - e . ) for running tests
- - install - deno Install the Deno runtime using the official installer
- - deno - version Pin a specific Deno version to install ( e . g . , v1 .34 .3 )
2025-12-17 14:17:46 -08:00
- - upgrade - pip Upgrade pip , setuptools , and wheel before installing deps
"""
from __future__ import annotations
import argparse
import subprocess
import sys
from pathlib import Path
2025-12-17 17:42:46 -08:00
import platform
import shutil
2025-12-17 14:17:46 -08:00
def run ( cmd : list [ str ] ) - > None :
print ( f " > { ' ' . join ( cmd ) } " )
subprocess . check_call ( cmd )
def playwright_package_installed ( ) - > bool :
try :
import playwright # type: ignore
return True
except Exception :
return False
2025-12-17 17:42:46 -08:00
def _build_playwright_install_cmd ( browsers : str | None ) - > list [ str ] :
""" Return the command to install Playwright browsers.
- If browsers is None or empty : default to install Chromium only .
- If browsers contains ' all ' : install all engines by running ' playwright install ' with no extra args .
- Otherwise , validate entries and return a command that installs the named engines .
"""
base = [ sys . executable , " -m " , " playwright " , " install " ]
if not browsers :
return base + [ " chromium " ]
items = [ b . strip ( ) . lower ( ) for b in browsers . split ( " , " ) if b . strip ( ) ]
if not items :
return base + [ " chromium " ]
if " all " in items :
return base
allowed = { " chromium " , " firefox " , " webkit " }
invalid = [ b for b in items if b not in allowed ]
if invalid :
raise ValueError ( f " invalid browsers specified: { invalid } . Valid choices: chromium, firefox, webkit, or ' all ' " )
return base + items
def _install_deno ( version : str | None = None ) - > int :
""" Install Deno runtime for the current platform.
Uses the official Deno install scripts :
- Unix / macOS : curl - fsSL https : / / deno . land / x / install / install . sh | sh [ - s < version > ]
- Windows : powershell iwr https : / / deno . land / x / install / install . ps1 - useb | iex ; Install - Deno [ - Version < version > ]
Returns exit code 0 on success , non - zero otherwise .
"""
system = platform . system ( ) . lower ( )
try :
if system == " windows " :
# Use official PowerShell installer
if version :
ver = version if version . startswith ( " v " ) else f " v { version } "
ps_cmd = f " iwr https://deno.land/x/install/install.ps1 -useb | iex; Install-Deno -Version { ver } "
else :
ps_cmd = " iwr https://deno.land/x/install/install.ps1 -useb | iex "
run ( [ " powershell " , " -NoProfile " , " -ExecutionPolicy " , " Bypass " , " -Command " , ps_cmd ] )
else :
# POSIX: use curl + sh installer
if version :
ver = version if version . startswith ( " v " ) else f " v { version } "
cmd = f " curl -fsSL https://deno.land/x/install/install.sh | sh -s { ver } "
else :
cmd = " curl -fsSL https://deno.land/x/install/install.sh | sh "
run ( [ " sh " , " -c " , cmd ] )
# Check that 'deno' is now available in PATH
if shutil . which ( " deno " ) :
print ( f " Deno installed at: { shutil . which ( ' deno ' ) } " )
return 0
else :
print ( " Deno installation completed but ' deno ' not found in PATH. You may need to add Deno ' s bin directory to your PATH manually. " , file = sys . stderr )
return 1
except subprocess . CalledProcessError as exc :
print ( f " Deno install failed: { exc } " , file = sys . stderr )
return int ( exc . returncode or 1 )
2025-12-17 14:17:46 -08:00
def main ( ) - > int :
parser = argparse . ArgumentParser ( description = " Setup Medios-Macina: install deps and Playwright browsers " )
parser . add_argument ( " --skip-deps " , action = " store_true " , help = " Skip installing Python dependencies from requirements.txt " )
parser . add_argument ( " --no-playwright " , action = " store_true " , help = " Skip running ' playwright install ' (only install packages) " )
parser . add_argument ( " --playwright-only " , action = " store_true " , help = " Only run ' playwright install ' (skips dependency installation) " )
2025-12-17 17:42:46 -08:00
parser . add_argument ( " --browsers " , type = str , default = " chromium " , help = " Comma-separated list of browsers to install: chromium,firefox,webkit or ' all ' (default: chromium) " )
parser . add_argument ( " --install-editable " , action = " store_true " , help = " Install the project in editable mode (pip install -e .) for running tests " )
deno_group = parser . add_mutually_exclusive_group ( )
deno_group . add_argument ( " --install-deno " , action = " store_true " , help = " Install the Deno runtime (default behavior; kept for explicitness) " )
deno_group . add_argument ( " --no-deno " , action = " store_true " , help = " Skip installing Deno runtime (opt out) " )
parser . add_argument ( " --deno-version " , type = str , default = None , help = " Specific Deno version to install (e.g., v1.34.3) " )
2025-12-17 14:17:46 -08:00
parser . add_argument ( " --upgrade-pip " , action = " store_true " , help = " Upgrade pip/setuptools/wheel before installing requirements " )
args = parser . parse_args ( )
repo_root = Path ( __file__ ) . resolve ( ) . parent . parent
if sys . version_info < ( 3 , 8 ) :
print ( " Warning: Python 3.8+ is recommended. " , file = sys . stderr )
try :
if args . playwright_only :
if not playwright_package_installed ( ) :
print ( " ' playwright ' package not found; installing it via pip... " )
run ( [ sys . executable , " -m " , " pip " , " install " , " playwright " ] )
print ( " Installing Playwright browsers (this may download several hundred MB)... " )
2025-12-17 17:42:46 -08:00
try :
cmd = _build_playwright_install_cmd ( args . browsers )
except ValueError as exc :
print ( f " Error: { exc } " , file = sys . stderr )
return 2
run ( cmd )
2025-12-17 14:17:46 -08:00
print ( " Playwright browsers installed successfully. " )
return 0
if args . upgrade_pip :
print ( " Upgrading pip, setuptools, and wheel... " )
run ( [ sys . executable , " -m " , " pip " , " install " , " --upgrade " , " pip " , " setuptools " , " wheel " ] )
if not args . skip_deps :
req_file = repo_root / " requirements.txt "
if not req_file . exists ( ) :
print ( f " requirements.txt not found at { req_file } ; skipping dependency installation. " , file = sys . stderr )
else :
print ( f " Installing Python dependencies from { req_file } ... " )
run ( [ sys . executable , " -m " , " pip " , " install " , " -r " , str ( req_file ) ] )
if not args . no_playwright :
if not playwright_package_installed ( ) :
print ( " ' playwright ' package not installed; installing it... " )
run ( [ sys . executable , " -m " , " pip " , " install " , " playwright " ] )
print ( " Installing Playwright browsers (this may download several hundred MB)... " )
2025-12-17 17:42:46 -08:00
try :
cmd = _build_playwright_install_cmd ( args . browsers )
except ValueError as exc :
print ( f " Error: { exc } " , file = sys . stderr )
return 2
run ( cmd )
# Optional: install the project in editable mode so tests can import the package
if args . install_editable :
print ( " Installing project in editable mode (pip install -e .) ... " )
run ( [ sys . executable , " -m " , " pip " , " install " , " -e " , " . " ] )
# Optional: install Deno runtime (default: install unless --no-deno is passed)
install_deno_requested = True
if getattr ( args , " no_deno " , False ) :
install_deno_requested = False
elif getattr ( args , " install_deno " , False ) :
install_deno_requested = True
if install_deno_requested :
print ( " Installing Deno runtime... " )
rc = _install_deno ( args . deno_version )
if rc != 0 :
print ( " Deno installation failed. " , file = sys . stderr )
return rc
2025-12-17 14:17:46 -08:00
print ( " Setup complete. " )
return 0
except subprocess . CalledProcessError as exc :
print ( f " Error: command failed with exit { exc . returncode } : { exc } " , file = sys . stderr )
return int ( exc . returncode or 1 )
except Exception as exc : # pragma: no cover - defensive
print ( f " Unexpected error: { exc } " , file = sys . stderr )
return 2
if __name__ == " __main__ " :
raise SystemExit ( main ( ) )