Source code for airbase.cli

from __future__ import annotations

import asyncio
from enum import Enum
from pathlib import Path
from typing import List, Optional

import typer

from . import __version__
from .csv_api import Source
from .csv_api import download as download_csv
from .parquet_api import AggregationType, Dataset
from .parquet_api import download as download_parquet
from .summary import DB

main = typer.Typer(add_completion=False, no_args_is_help=True)


[docs]class Country(str, Enum): _ignore_ = "country Country" # type:ignore[misc] Country = vars() for country in sorted(DB.COUNTRY_CODES): Country[country] = country def __str__(self) -> str: return self.name
[docs]class Pollutant(str, Enum): _ignore_ = "poll Pollutant" # type:ignore[misc] Pollutant = vars() for poll in sorted(DB.POLLUTANTS, key=lambda poll: len(poll)): Pollutant[poll] = poll def __str__(self) -> str: return self.name
[docs]class Frequency(str, Enum): _ignore_ = "agg Frequency" # type:ignore[misc] Frequency = vars() for agg in AggregationType: Frequency[agg.name.casefold()] = agg.name.casefold() def __str__(self) -> str: return self.name @property def aggregation_type(self) -> AggregationType: return AggregationType[self.name.capitalize()]
[docs]def version_callback(value: bool): if not value: return typer.echo(f"{__package__} v{__version__}") raise typer.Exit()
[docs]@main.callback() def callback( version: Optional[bool] = typer.Option( None, "--version", "-V", callback=version_callback ), ): """Download Air Quality Data from the European Environment Agency (EEA)"""
COUNTRIES = typer.Option([], "-c", "--country") POLLUTANTS = typer.Option([], "-p", "--pollutant") CITIES = typer.Option([], "-C", "--city", help="Only from selected <cities>.") FREQUENCY = typer.Option( None, "--aggregation-type", "--frequency", "-F", help="Only hourly data, daily data or other aggregation frequency.", ) METADATA = typer.Option( False, "-M", "--metadata", help="Download station metadata." ) SUMMARY = typer.Option( False, "-n", "--dry-run", "--summary", help="Total download files/size, nothing will be downloaded.", ) FLAT_DIR = typer.Option( False, "--subdir/--no-subdir", help="Download files for different counties to different sub directories.", ) COUNTRY_SUBDIR = typer.Option( True, "--subdir/--no-subdir", help="Download files for different counties to different sub directories.", ) OVERWRITE = typer.Option( False, "-O", "--overwrite", help="Re-download existing files." ) QUIET = typer.Option(False, "-q", "--quiet", help="No progress-bar.")
[docs]@main.command("download", no_args_is_help=True) def legacy( countries: List[Country] = COUNTRIES, pollutants: List[Pollutant] = POLLUTANTS, cities: List[str] = CITIES, metadata: bool = METADATA, path: Path = typer.Option( "data", "--path", exists=True, dir_okay=True, writable=True ), year: int = typer.Option(2024, "--year", min=2013, max=2024), country_subdir: bool = FLAT_DIR, overwrite: bool = OVERWRITE, quiet: bool = QUIET, ): """ Air quality data in in CSV format. **End of life 2024**. \b The service providing air quality data in CSV format will cease operations by the end of 2024. Until then it will provide only **unverified** data (E2a) for 2024. \b Use -c/--country and -p/--pollutant to restrict the download specific countries and pollutants, e.g. - download only Norwegian, Danish and Finish sites airbase download -c NO -c DK -c FI - download only SO2, PM10 and PM2.5 observations airbase download -p SO2 -p PM10 -p PM2.5 \b Use -C/--city to further restrict the download to specific cities, e.g. - download only PM10 and PM2.5 from Valletta, the Capital of Malta airbase download -C Valletta -c MT -p PM10 -p PM2.5 """ asyncio.run( download( Source.ALL, path, year=year, countries=countries, pollutants=pollutants, cities=cities, metadata=metadata, country_subdir=country_subdir, overwrite=overwrite, quiet=quiet, ) )
[docs]async def download( dataset: Dataset | Source, path: Path, *, countries: list[Country], pollutants: list[Pollutant], cities: list[str], metadata: bool, country_subdir: bool, overwrite: bool, quiet: bool, frequency: Frequency | None = None, summary_only: bool | None = None, year: int | None = None, ) -> None: """download CSV or Parquet files from corresponding API""" if isinstance(dataset, Dataset): if summary_only is None: raise typer.BadParameter("missing --dry-run/--summary option") await download_parquet( dataset, path, countries=frozenset(map(str, countries)), pollutants=frozenset(map(str, pollutants)), cities=frozenset(cities), frequency=None if frequency is None else frequency.aggregation_type, metadata=metadata, summary_only=summary_only, country_subdir=country_subdir, overwrite=overwrite, quiet=quiet, ) return if isinstance(dataset, Source): if year is None: raise typer.BadParameter("missing --year option") await download_csv( dataset, year, path, countries=frozenset(map(str, countries)), pollutants=frozenset(map(str, pollutants)), cities=frozenset(cities), metadata=metadata, country_subdir=country_subdir, overwrite=overwrite, quiet=quiet, ) return # should never reach raise ValueError( f"Unsupported dataset, summary, year: {dataset}, {summary_only}, {year}." )
[docs]@main.command(no_args_is_help=True) def historical( countries: List[Country] = COUNTRIES, pollutants: List[Pollutant] = POLLUTANTS, cities: List[str] = CITIES, frequency: Optional[Frequency] = FREQUENCY, metadata: bool = METADATA, path: Path = typer.Option( "data/historical", "--path", exists=True, dir_okay=True, writable=True ), summary_only: bool = SUMMARY, country_subdir: bool = COUNTRY_SUBDIR, overwrite: bool = OVERWRITE, quiet: bool = QUIET, ): """ Historical Airbase data delivered between 2002 and 2012 before Air Quality Directive 2008/50/EC entered into force. \b Use -c/--country and -p/--pollutant to restrict the download specific countries and pollutants, e.g. - download only Norwegian, Danish and Finish sites airbase download -c NO -c DK -c FI - download only SO2, PM10 and PM2.5 observations airbase download -p SO2 -p PM10 -p PM2.5 \b Use -C/--city to further restrict the download to specific cities, e.g. - download only PM10 and PM2.5 from Valletta, the Capital of Malta airbase download -C Valletta -c MT -p PM10 -p PM2.5 """ asyncio.run( download( Dataset.Historical, path, countries=countries, pollutants=pollutants, cities=cities, frequency=frequency, metadata=metadata, summary_only=summary_only, country_subdir=country_subdir, overwrite=overwrite, quiet=quiet, ) )
[docs]@main.command(no_args_is_help=True) def verified( countries: List[Country] = COUNTRIES, pollutants: List[Pollutant] = POLLUTANTS, cities: List[str] = CITIES, frequency: Optional[Frequency] = FREQUENCY, metadata: bool = METADATA, path: Path = typer.Option( "data/verified", "--path", exists=True, dir_okay=True, writable=True ), summary_only: bool = SUMMARY, country_subdir: bool = COUNTRY_SUBDIR, overwrite: bool = OVERWRITE, quiet: bool = QUIET, ): """ Verified data (E1a) from 2013 to 2023 reported by countries by 30 September each year for the previous year. \b Use -c/--country and -p/--pollutant to restrict the download specific countries and pollutants, e.g. - download only Norwegian, Danish and Finish sites airbase download -c NO -c DK -c FI - download only SO2, PM10 and PM2.5 observations airbase download -p SO2 -p PM10 -p PM2.5 \b Use -C/--city to further restrict the download to specific cities, e.g. - download only PM10 and PM2.5 from Valletta, the Capital of Malta airbase download -C Valletta -c MT -p PM10 -p PM2.5 """ asyncio.run( download( Dataset.Verified, path, countries=countries, pollutants=pollutants, cities=cities, frequency=frequency, metadata=metadata, summary_only=summary_only, country_subdir=country_subdir, overwrite=overwrite, quiet=quiet, ) )
[docs]@main.command(no_args_is_help=True) def unverified( countries: List[Country] = COUNTRIES, pollutants: List[Pollutant] = POLLUTANTS, cities: List[str] = CITIES, frequency: Optional[Frequency] = FREQUENCY, metadata: bool = METADATA, path: Path = typer.Option( "data/unverified", "--path", exists=True, dir_okay=True, writable=True ), summary_only: bool = SUMMARY, country_subdir: bool = COUNTRY_SUBDIR, overwrite: bool = OVERWRITE, quiet: bool = QUIET, ): """ Unverified data transmitted continuously (Up-To-Date/UTD/E2a) data from the beginning of 2024. \b Use -c/--country and -p/--pollutant to restrict the download specific countries and pollutants, e.g. - download only Norwegian, Danish and Finish sites airbase download -c NO -c DK -c FI - download only SO2, PM10 and PM2.5 observations airbase download -p SO2 -p PM10 -p PM2.5 \b Use -C/--city to further restrict the download to specific cities, e.g. - download only PM10 and PM2.5 from Valletta, the Capital of Malta airbase download -C Valletta -c MT -p PM10 -p PM2.5 """ asyncio.run( download( Dataset.Unverified, path, countries=countries, pollutants=pollutants, cities=cities, frequency=frequency, metadata=metadata, summary_only=summary_only, country_subdir=country_subdir, overwrite=overwrite, quiet=quiet, ) )