Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Co vs CO #43

Merged
merged 7 commits into from
Apr 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions .github/workflows/cicd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ jobs:
matrix:
python: [3.7, 3.8, 3.9, '3.10', '3.11']
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python }}
- run: |
Expand All @@ -25,8 +25,8 @@ jobs:
needs: unit-test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: 3.x
- run: |
Expand All @@ -37,18 +37,18 @@ jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: pre-commit/action@v2.0.3
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- uses: pre-commit/action@v3.0.0
with:
extra_args: --all-files

build-and-deploy:
needs: [unit-test, integration-test, lint]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: 3.x
- run: |
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ repos:
exclude: '(docs/.*)|(setup\.py)'
additional_dependencies: [types-aiofiles, types-requests]
- repo: https://github.com/pycqa/isort
rev: 5.10.1
rev: 5.12.0
hooks:
- id: isort
name: isort (python)
200 changes: 126 additions & 74 deletions airbase/cli.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
from __future__ import annotations

import sys
from datetime import date
from enum import Enum
from pathlib import Path
from typing import List

import typer
import click

from . import __version__
from .airbase import AirbaseClient

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


Expand All @@ -39,39 +35,97 @@ def __str__(self) -> str:
return self.name


def version_callback(value: bool):
if not value:
return
@click.group(invoke_without_command=True, no_args_is_help=True)
@click.option(
"--version",
"-V",
is_flag=True,
help=f"Show {__package__} version and exit.",
)
def main(version: bool):
"""Download Air Quality Data from the European Environment Agency (EEA)"""
if version:
click.echo(f"{__package__} v{__version__}")
sys.exit(0)


countries = click.option(
"-c",
"--country",
"countries",
type=click.Choice(Country), # type:ignore [arg-type]
multiple=True,
)
country = click.argument(
"country",
type=click.Choice(Country), # type:ignore [arg-type]
)

pollutants = click.option(
"-p",
"--pollutant",
"pollutants",
type=click.Choice(Pollutant), # type:ignore [arg-type]
multiple=True,
)
pollutant = click.argument(
"pollutant",
type=click.Choice(Pollutant), # type:ignore [arg-type]
)


typer.echo(f"{__package__} v{__version__}")
raise typer.Exit()
path = click.option(
"--path",
default="data",
type=click.Path(exists=True, dir_okay=True, writable=True),
)
year = click.option("--year", default=date.today().year, type=int)
overwrite = click.option(
"-O",
"--overwrite",
is_flag=True,
help="Re-download existing files.",
)
quiet = click.option(
"-q",
"--quiet",
is_flag=True,
help="No progress-bar.",
)


@main.callback()
def root_options(
version: bool = typer.Option(
False,
"--version",
"-V",
callback=version_callback,
help=f"Show {__package__} version and exit.",
),
def _download(
countries: list[Country],
pollutants: list[Pollutant],
path: Path,
year: int,
overwrite: bool,
quiet: bool,
):
"""Download Air Quality Data from the European Environment Agency (EEA)"""
request = client.request(
countries or None, # type:ignore[arg-type]
pollutants or None, # type:ignore[arg-type]
year_from=str(year),
year_to=str(year),
verbose=not quiet,
)
request.download_to_directory(path, skip_existing=not overwrite)


@main.command()
@countries
@pollutants
@path
@year
@overwrite
@quiet
def download(
countries: List[Country] = typer.Option([], "--country", "-c"),
pollutants: List[Pollutant] = typer.Option([], "--pollutant", "-p"),
path: Path = typer.Option(
"data", exists=True, dir_okay=True, writable=True
),
year: int = typer.Option(date.today().year),
overwrite: bool = typer.Option(
False, "--overwrite", "-O", help="Re-download existing files."
),
quiet: bool = typer.Option(False, "--quiet", "-q", help="No progress-bar."),
countries: list[Country],
pollutants: list[Pollutant],
path: Path,
year: int,
overwrite: bool,
quiet: bool,
):
"""Download all pollutants for all countries

Expand All @@ -82,74 +136,72 @@ def download(
- download only SO2, PM10 and PM2.5 observations
airbase download -p SO2 -p PM10 -p PM2.5
"""

request = client.request(
countries or None, # type:ignore[arg-type]
pollutants or None, # type:ignore[arg-type]
year_from=str(year),
year_to=str(year),
verbose=not quiet,
)
request.download_to_directory(path, skip_existing=not overwrite)
_download(countries, pollutants, path, year, overwrite, quiet)


def deprecation_message(old: str, new: str): # pragma: no cover
old = typer.style(f"{__package__} {old}", fg=typer.colors.RED, bold=True)
new = typer.style(f"{__package__} {new}", fg=typer.colors.GREEN, bold=True)
typer.echo(
old = click.style(f"{__package__} {old}", fg="red", bold=True)
new = click.style(f"{__package__} {new}", fg="green", bold=True)
click.echo(
f"{old} has been deprecated and will be removed on v1. Use {new} all instead.",
)


@main.command(name="all")
@countries
@pollutants
@path
@year
@overwrite
@quiet
def download_all(
countries: List[Country] = typer.Option([], "--country", "-c"),
pollutants: List[Pollutant] = typer.Option([], "--pollutant", "-p"),
path: Path = typer.Option(
"data", exists=True, dir_okay=True, writable=True
),
year: int = typer.Option(date.today().year),
overwrite: bool = typer.Option(
False, "--overwrite", "-O", help="Re-download existing files."
),
quiet: bool = typer.Option(False, "--quiet", "-q", help="No progress-bar."),
countries: list[Country],
pollutants: list[Pollutant],
path: Path,
year: int,
overwrite: bool,
quiet: bool,
): # pragma: no cover
"""Download all pollutants for all countries (deprecated)"""
deprecation_message("all", "download")
download(countries, pollutants, path, year, overwrite, quiet)
_download(countries, pollutants, path, year, overwrite, quiet)


@main.command(name="country")
@country
@pollutants
@path
@year
@overwrite
@quiet
def download_country(
country: Country,
pollutants: List[Pollutant] = typer.Option([], "--pollutant", "-p"),
path: Path = typer.Option(
"data", exists=True, dir_okay=True, writable=True
),
year: int = typer.Option(date.today().year),
overwrite: bool = typer.Option(
False, "--overwrite", "-O", help="Re-download existing files."
),
quiet: bool = typer.Option(False, "--quiet", "-q", help="No progress-bar."),
pollutants: list[Pollutant],
path: Path,
year: int,
overwrite: bool,
quiet: bool,
): # pragma: no cover
"""Download specific pollutants for one country (deprecated)"""
deprecation_message("country", "download")
download([country], pollutants, path, year, overwrite, quiet)
_download([country], pollutants, path, year, overwrite, quiet)


@main.command(name="pollutant")
@pollutant
@countries
@path
@year
@overwrite
@quiet
def download_pollutant(
pollutant: Pollutant,
countries: List[Country] = typer.Option([], "--country", "-c"),
path: Path = typer.Option(
"data", exists=True, dir_okay=True, writable=True
),
year: int = typer.Option(date.today().year),
overwrite: bool = typer.Option(
False, "--overwrite", "-O", help="Re-download existing files."
),
quiet: bool = typer.Option(False, "--quiet", "-q", help="No progress-bar."),
countries: list[Country],
path: Path,
year: int,
overwrite: bool,
quiet: bool,
): # pragma: no cover
"""Download specific countries for one pollutant (deprecated)"""
deprecation_message("pollutant", "download")
download(countries, [pollutant], path, year, overwrite, quiet)
_download(countries, [pollutant], path, year, overwrite, quiet)
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ install_requires =
importlib_resources; python_version < "3.11"
tqdm
typing_extensions; python_version < "3.8"
typer
click
packages = find:
include_package_data = True

Expand Down
22 changes: 16 additions & 6 deletions tests/integration/test_cli.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
from pathlib import Path

from typer.testing import CliRunner
import pytest
from click.testing import CliRunner

from airbase.cli import main

runner = CliRunner()


def test_download(tmp_path: Path):
country, year, pollutant, id = "NO", 2021, "NO2", 8
@pytest.mark.parametrize(
"country,year,pollutant,id",
(
pytest.param("NO", 2021, "NO2", 8, id="NO2"),
pytest.param("NO", 2021, "CO", 10, id="CO"),
),
)
def test_download(
country: str, year: int, pollutant: str, id: int, tmp_path: Path
):
options = f"download --quiet --country {country} --pollutant {pollutant} --year {year} --path {tmp_path}"
result = runner.invoke(main, options.split())
assert result.exit_code == 0
with runner.isolated_filesystem(temp_dir=tmp_path):
result = runner.invoke(main, options.split())
assert result.exit_code == 0
files = tmp_path.glob(f"{country}_{id}_*_{year}_timeseries.csv")

files = tmp_path.glob(f"{country}_{id}_*_{year}_timeseries.csv")
assert list(files)
6 changes: 4 additions & 2 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from __future__ import annotations

import pytest
from typer.testing import CliRunner
from click.testing import CliRunner

from airbase import __version__
from airbase.cli import Country, Pollutant, main
Expand All @@ -22,4 +24,4 @@ def test_version(options: str):
result = runner.invoke(main, options.split())
assert result.exit_code == 0
assert "airbase" in result.output
assert __version__ in result.output
assert str(__version__) in result.output