diff --git a/frontools/cli.py b/frontools/cli.py index 8992b89..acbe581 100644 --- a/frontools/cli.py +++ b/frontools/cli.py @@ -9,7 +9,7 @@ from click import Path as PathArgument from click import argument, group, option, pass_context, pass_obj from frontools.cache import Cache -from frontools.config import Config +from frontools.context import Context from frontools.css import css_diff from frontools.screenshot import screenshot_diff @@ -62,11 +62,15 @@ async def main( exclude_urls: list[str], ) -> None: """Utilities for EO frontend development.""" - - ctx.obj = await Config.load( + ctx.obj = await Context.load( config_file, source, not no_cache, include_urls, exclude_urls ) + def _on_close(): + ctx.obj.print_error_summary() + + ctx.call_on_close(_on_close) + @main.command(name="prune-caches") @argument("cache_names", nargs=-1) @@ -79,12 +83,14 @@ def prune_caches(cache_names: list[str]) -> None: @argument("right_source", type=str) @pass_obj @_async_command -async def css_diff_cli(config: Config, right_source: str) -> None: +async def css_diff_cli(context: Context, right_source: str) -> None: """Diff CSS""" - for _, site in config.sites: + for _, site in context.config.sites: for site_url in site.urls: await css_diff( - site_url, config.default_source, config.get_source(right_source) + site_url, + context.config.default_source, + context.config.get_source(right_source), ) @@ -95,13 +101,13 @@ async def css_diff_cli(config: Config, right_source: str) -> None: @_async_command @pass_obj async def screenshot_diff_cli( - config: Config, + context: Context, source: str, output_directory: Optional[str], resolution: Optional[str], ) -> None: """Generate screenshot diffs""" - await screenshot_diff(config, source, output_directory, resolution=resolution) + await screenshot_diff(context, source, output_directory, resolution=resolution) if __name__ == "__main__": diff --git a/frontools/context.py b/frontools/context.py new file mode 100644 index 0000000..9c72e38 --- /dev/null +++ b/frontools/context.py @@ -0,0 +1,43 @@ +"""Global context object""" +from pathlib import Path +from typing import Optional + +from click import echo + +from frontools.config import Config + + +class Context: + """Configuration object""" + + def __init__(self, config: Config) -> None: + """Load config from the given path""" + + self._config = config + self._errors: list[str] = [] + + @staticmethod + async def load( + config_path: Optional[Path], + default_source_name: Optional[str], + use_cache: bool, + include_urls: list[str], + exclude_urls: list[str], + ) -> "Context": + config = await Config.load( + config_path, default_source_name, use_cache, include_urls, exclude_urls + ) + return Context(config) + + def add_error(self, message: str) -> None: + self._errors.append(message) + + def print_error_summary(self) -> None: + echo("***** Error summary :") + for error in self._errors: + echo(error, err=True) + + @property + def config(self) -> Config: + """Get configuration object for this run""" + return self._config diff --git a/frontools/screenshot.py b/frontools/screenshot.py index 6bb0c52..d2ac615 100644 --- a/frontools/screenshot.py +++ b/frontools/screenshot.py @@ -3,9 +3,10 @@ from pathlib import Path from tempfile import NamedTemporaryFile from typing import Optional +from aiohttp import ClientConnectionError from PIL import Image, ImageChops -from frontools import Config +from frontools.context import Context from frontools.sources import Browser from frontools.utils import ( get_default_screenshot_directory, @@ -15,12 +16,13 @@ from frontools.utils import ( async def screenshot_diff( - config: Config, + context: Context, right_source_name: str, output_directory: Optional[str], resolution: Optional[str] = None, ) -> None: """Compare pages with or without local css""" + config = context.config if output_directory is None: output_path = get_default_screenshot_directory() @@ -42,7 +44,11 @@ async def screenshot_diff( async with right_source.get_browser( width=width, height=height ) as right_browser: - urls = [(site_name, url) for (site_name, site) in config.sites for url in site.urls] + urls = [ + (site_name, url) + for (site_name, site) in config.sites + for url in site.urls + ] await report_progress( "Screenshoting", @@ -50,7 +56,12 @@ async def screenshot_diff( ( url, _diff_url( - left_browser, right_browser, url, output_path, site_name + context, + left_browser, + right_browser, + url, + output_path, + site_name, ), ) for (site_name, url) in urls @@ -59,35 +70,47 @@ async def screenshot_diff( ) -async def _diff_url(left: Browser, right: Browser, url: str, output_path: Path, site_name: str) -> None: +async def _diff_url( + context: Context, + left: Browser, + right: Browser, + url: str, + output_path: Path, + site_name: str, +) -> None: try: left_bytes = await _screenshot_url(left, url) right_bytes = await _screenshot_url(right, url) + except ClientConnectionError as exception: + context.add_error(f'{site_name} : error while loading {url} : {exception}') + return - with NamedTemporaryFile(mode="wb") as left_file: - left_file.write(left_bytes) - left_image = Image.open(left_file.name).convert('RGB') + with NamedTemporaryFile(mode="wb") as left_file: + left_file.write(left_bytes) + left_image = Image.open(left_file.name).convert("RGB") - with NamedTemporaryFile(mode="wb") as right_file: - right_file.write(right_bytes) - right_image = Image.open(right_file.name).convert('RGB') + with NamedTemporaryFile(mode="wb") as right_file: + right_file.write(right_bytes) + right_image = Image.open(right_file.name).convert("RGB") - diff = ImageChops.difference(left_image, right_image) + diff = ImageChops.difference(left_image, right_image) - if not diff.getbbox(): - return + if not diff.getbbox(): + return - url_slug = get_url_slug(url) - if not output_path.is_dir(): - output_path.mkdir() + url_slug = get_url_slug(url) + if not output_path.is_dir(): + output_path.mkdir() - with open(output_path / f"{site_name}_{url_slug}_left", "wb") as screenshot_file: - screenshot_file.write(left_bytes) + with open( + output_path / f"{site_name}_{url_slug}_left", "wb" + ) as screenshot_file: + screenshot_file.write(left_bytes) - with open(output_path / f"{site_name}_{url_slug}_right", "wb") as screenshot_file: - screenshot_file.write(right_bytes) - except Exception as ex: - print(f"Error while diffing {url} : {ex}") + with open( + output_path / f"{site_name}_{url_slug}_right", "wb" + ) as screenshot_file: + screenshot_file.write(right_bytes) async def _screenshot_url(browser: Browser, url: str) -> bytes: