Skip to content
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
2 changes: 1 addition & 1 deletion .github/workflows/ci-cd-mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
with:
path: "docs/site/"
publish:
if: success() && github.ref == 'refs/heads/main'
if: success() && startsWith(github.ref, 'refs/tags')
name: Publish doc
needs: build
permissions:
Expand Down
10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,20 @@ repos:
- id: check-added-large-files
args: [--maxkb=500]
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.3
rev: v0.8.6
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.13.0
rev: v1.14.1
hooks:
- id: mypy
args: [--config-file=pyproject.toml]
files: src
additional_dependencies: [pydantic~=2.0,types-pytz,types-requests,types-python-dateutil]
- repo: https://github.com/gitleaks/gitleaks
rev: v8.21.2
rev: v8.22.1
hooks:
- id: gitleaks
- repo: https://github.com/pypa/pip-audit
Expand All @@ -49,12 +49,12 @@ repos:
- id: pip-audit
args: [--skip-editable]
- repo: https://github.com/compilerla/conventional-pre-commit
rev: v3.6.0
rev: v4.0.0
hooks:
- id: conventional-pre-commit
stages: [commit-msg]
args: [feat, fix, ci, chore, test, docs]
- repo: https://github.com/kynan/nbstripout
rev: 0.7.1
rev: 0.8.1
hooks:
- id: nbstripout
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
</p>
<p align="center">
<img src="https://github.com/MAIF/meteole/actions/workflows/ci-cd.yml/badge.svg?branch=main" alt="CI">
<img src="https://img.shields.io/badge/coverage-86%25-dark_green" alt="Coverage">
<img src="https://img.shields.io/badge/coverage-89%25-dark_green" alt="Coverage">
<img src="https://img.shields.io/pypi/v/meteole" alt="Versions">
<img src="https://img.shields.io/pypi/pyversions/meteole" alt="Python">
<img src="https://img.shields.io/pypi/dm/meteole" alt="Downloads">
Expand Down Expand Up @@ -120,7 +120,7 @@ vigi.get_vignette()

<img src="docs/pages/assets/img/png/vignette_exemple.png" width="600" height="300" alt="vignette de vigilance">

To have more documentation from MeteoFrance in Vigilance Bulletin :
To have more documentation from Meteo-France in Vigilance Bulletin :
- [Meteo France Documentation](https://donneespubliques.meteofrance.fr/?fond=produit&id_produit=305&id_rubrique=50)

## Contributing
Expand Down
22 changes: 10 additions & 12 deletions docs/mkdocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,23 @@ repo_name: MAIF/meteole
site_author: OSSbyMAIF Team
docs_dir: pages
theme:
name: 'material'
name: material
logo: assets/img/svg/meteole-fond-clair.svg
favicon: assets/img/svg/meteole-git.svg
favicon: assets/img/png/meteole-git.png
palette:
# Palette toggle for automatic mode
- media: "(prefers-color-scheme)"
toggle:
icon: material/brightness-auto
name: Switch to light mode
primary: white
accent: red
primary: light green
accent: lime

# Palette toggle for light mode
- media: "(prefers-color-scheme: light)"
scheme: default
primary: white
accent: red
primary: light green
accent: lime
toggle:
icon: material/brightness-7
name: Switch to dark mode
Expand All @@ -30,13 +30,13 @@ theme:
- media: "(prefers-color-scheme: dark)"
scheme: slate
primary: black
accent: red
accent: lime
toggle:
icon: material/brightness-4
name: Switch to system preference
font:
text: 'Roboto'
code: 'Roboto Mono'
text: Urbanist
code: Source Code Pro
language: en
features:
- content.tabs.link
Expand Down Expand Up @@ -81,6 +81,4 @@ nav:
- User Guide:
- How to: how_to.md
- Advanced User Guide:
- Coverages: coverage_parameters.md
extra_css:
- assets/css/mkdocs_extra.css
- Coverages: coverage_parameters.md
Binary file added docs/pages/assets/img/png/meteole-git.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion docs/pages/assets/img/svg/meteole-git.svg

This file was deleted.

3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ build-backend = "setuptools.build_meta"

[project]
name = "meteole"
version = "0.0.1"
version = "0.1.0b1"
requires-python = ">3.8.0"
description = "A Python client library for forecast model APIs (e.g., Météo-France)."
readme = "README.md"
license = {text = "Apache-2.0"}
authors = [
{name = "ThomasBouche"},
{name = "develop-cs"},
{name = "GratienDSX"},
]

Expand Down
19 changes: 0 additions & 19 deletions src/meteole/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import logging
from importlib.metadata import version

from meteole._arome import AromeForecast
Expand All @@ -8,21 +7,3 @@
__all__ = ["AromeForecast", "ArpegeForecast", "Vigilance"]

__version__ = version("meteole")


def setup_logger():
"""Setup logger with proper StreamHandler and formatter"""
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

handler = logging.StreamHandler()
handler.setLevel(logging.INFO)

# formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
formatter = logging.Formatter("%(message)s")
handler.setFormatter(formatter)

return logger.addHandler(handler)


logger = setup_logger()
30 changes: 19 additions & 11 deletions src/meteole/_arome.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
"""The interface for the observational data from the meteo-France API.

See :
- https://portail-api.meteofrance.fr/web/fr/api/arome
"""

from __future__ import annotations

import logging
from typing import final

from meteole.clients import BaseClient, MeteoFranceClient
from meteole.forecast import Forecast
from meteole.forecast import WeatherForecast

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -50,8 +44,17 @@


@final
class AromeForecast(Forecast):
"""Access the AROME numerical forecast data."""
class AromeForecast(WeatherForecast):
"""Access the AROME numerical weather forecast data from Meteo-France API.

Doc:
- https://portail-api.meteofrance.fr/web/fr/api/arome

Attributes:
territory: Covered area (e.g., FRANCE, ANTIL, ...).
precision: Precision value of the forecast.
capabilities: DataFrame containing details on all available coverage ids.
"""

# Model constants
MODEL_NAME: str = "arome"
Expand All @@ -62,9 +65,14 @@ class AromeForecast(Forecast):
DEFAULT_PRECISION: float = 0.01
CLIENT_CLASS: type[BaseClient] = MeteoFranceClient

def _validate_parameters(self):
"""Assert the parameters are valid."""
def _validate_parameters(self) -> None:
"""Check the territory and the precision parameters.

Raise:
ValueError: At least, one parameter is not good.
"""
if self.precision not in [0.01, 0.025]:
raise ValueError("Parameter `precision` must be in (0.01, 0.025). It is inferred from argument `territory`")

if self.territory not in AVAILABLE_AROME_TERRITORY:
raise ValueError(f"Parameter `territory` must be in {AVAILABLE_AROME_TERRITORY}")
43 changes: 23 additions & 20 deletions src/meteole/_arpege.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
"""The interface for the observational data from the meteo-France API.
See :
- https://portail-api.meteofrance.fr/web/fr/api/arpege
"""

from __future__ import annotations

from typing import Any, final

from meteole.clients import BaseClient, MeteoFranceClient
from meteole.forecast import Forecast
from meteole.forecast import WeatherForecast

AVAILABLE_ARPEGE_TERRITORY: list[str] = ["EUROPE", "GLOBE", "ATOURX", "EURAT"]

Expand Down Expand Up @@ -68,8 +62,17 @@


@final
class ArpegeForecast(Forecast):
"""Access the ARPEGE numerical forecast data."""
class ArpegeForecast(WeatherForecast):
"""Access the ARPEGE numerical weather forecast data from Meteo-France API.
Doc:
- https://portail-api.meteofrance.fr/web/fr/api/arpege
Attributes:
territory: Covered area (e.g., FRANCE, ANTIL, ...).
precision: Precision value of the forecast.
capabilities: DataFrame containing details on all available coverage ids.
"""

# Model constants
MODEL_NAME: str = "arpege"
Expand All @@ -87,24 +90,20 @@ def __init__(
territory: str = "EUROPE",
**kwargs: Any,
):
"""
Initializes an ArpegeForecast object for accessing ARPEGE forecast data.
"""Initializes an ArpegeForecast object.
The `precision` of the forecast is inferred from the specified `territory`.
Args:
territory (str, optional): The ARPEGE territory to fetch. Defaults to "EUROPE".
api_key (str | None, optional): The API key for authentication. Defaults to None.
token (str | None, optional): The API token for authentication. Defaults to None.
application_id (str | None, optional): The Application ID for authentication. Defaults to None.
cache_dir (str | None, optional): Path to the cache directory. Defaults to None.
If not provided, the cache directory is set to "/tmp/cache".
territory: The ARPEGE territory to fetch. Defaults to "EUROPE".
api_key: The API key for authentication. Defaults to None.
token: The API token for authentication. Defaults to None.
application_id: The Application ID for authentication. Defaults to None.
Notes:
- See `MeteoFranceClient` for additional details on the parameters `api_key`, `token`,
and `application_id`.
- Available territories are listed in the `AVAILABLE_TERRITORY` constant.
"""
super().__init__(
client=client,
Expand All @@ -113,7 +112,11 @@ def __init__(
**kwargs,
)

def _validate_parameters(self):
"""Assert the parameters are valid."""
def _validate_parameters(self) -> None:
"""Check the territory and the precision parameters.
Raise:
ValueError: At least, one parameter is not good.
"""
if self.territory not in AVAILABLE_ARPEGE_TERRITORY:
raise ValueError(f"The parameter precision must be in {AVAILABLE_ARPEGE_TERRITORY}")
35 changes: 15 additions & 20 deletions src/meteole/_vigilance.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,13 @@

@final
class Vigilance:
"""Wrapper around the meteo-France API for the vigilance data.
Ressources are:
"""Easy access to the vigilance data of Meteo-France.

Resources are:
- textesvigilance
- cartevigilance

Documentation
-------------
See:
Docs:
- https://portail-api.meteofrance.fr/web/fr/api/DonneesPubliquesVigilance
- https://donneespubliques.meteofrance.fr/client/document/descriptiftechnique_vigilancemetropole_
donneespubliques_v4_20230911_307.pdf
Expand All @@ -49,19 +48,18 @@ def __init__(
client: BaseClient | None = None,
**kwargs: Any,
) -> None:
"""TODO"""
"""Initialize attributes"""
if client is not None:
self._client = client
else:
# Try to instantiate it (can be user friendly)
self._client = MeteoFranceClient(**kwargs)

def get_bulletin(self) -> dict[str, Any]:
"""
Retrieve the vigilance bulletin.
"""Retrieve the vigilance bulletin.

Returns:
dict: a Dict representing the vigilance bulletin
Dictionary representing the vigilance bulletin
"""

path: str = self.VIGILANCE_BASE_PATH + self.API_VERSION + "/textesvigilance/encours"
Expand All @@ -72,7 +70,7 @@ def get_bulletin(self) -> dict[str, Any]:
return resp.json()

except MissingDataError as e:
if "no matching blob" in e.message:
if "no matching blob" in str(e):
logger.warning("Ongoing vigilance requires no publication")
else:
logger.error(f"Unexpected error: {e}")
Expand All @@ -82,11 +80,10 @@ def get_bulletin(self) -> dict[str, Any]:
return {}

def get_map(self) -> dict[str, Any]:
"""
Get the vigilance map with predicted risk displayed.
"""Get the vigilance map with predicted risk displayed.

Returns:
dict: a Dict with the predicted risk.
Dictionary with the predicted risk.
"""
path: str = self.VIGILANCE_BASE_PATH + self.API_VERSION + "/cartevigilance/encours"
logger.debug(f"GET {path}")
Expand All @@ -96,12 +93,12 @@ def get_map(self) -> dict[str, Any]:
return resp.json()

def get_phenomenon(self) -> tuple[pd.DataFrame, pd.DataFrame]:
"""
Get risk prediction by phenomenon and by domain.
"""Get risk prediction by phenomenon and by domain.

Returns:
pd.DataFrame: a DataFrame with phenomenon by id
pd.DataFrame: a DataFrame with phenomenon by domain
Tuple of:
A DataFrame with phenomenon by id
A DataFrame with phenomenon by domain
"""
df_carte = pd.DataFrame(self.get_map())
periods_data = df_carte.loc["periods", "product"]
Expand All @@ -128,9 +125,7 @@ def get_phenomenon(self) -> tuple[pd.DataFrame, pd.DataFrame]:
return df_phenomenon, df_timelaps

def get_vignette(self) -> None:
"""
Get png.
"""
"""Get png file."""
path: str = self.VIGILANCE_BASE_PATH + self.API_VERSION + "/vignettenationale-J-et-J1/encours"

logger.debug(f"GET {path}")
Expand Down
Loading
Loading