meteocatpy 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/.github/workflows/release.yml +33 -0
  2. package/.gitlab-ci.yml +46 -0
  3. package/.pre-commit-config.yaml +37 -0
  4. package/.releaserc +23 -0
  5. package/.releaserc.toml +14 -0
  6. package/AUTHORS.md +12 -0
  7. package/CHANGELOG.md +137 -0
  8. package/LICENSE +194 -0
  9. package/README.md +62 -0
  10. package/filetree.py +48 -0
  11. package/filetree.txt +48 -0
  12. package/meteocatpy/README.md +62 -0
  13. package/meteocatpy/__init__.py +27 -0
  14. package/meteocatpy/const.py +10 -0
  15. package/meteocatpy/data.py +140 -0
  16. package/meteocatpy/exceptions.py +35 -0
  17. package/meteocatpy/forecast.py +137 -0
  18. package/meteocatpy/helpers.py +46 -0
  19. package/meteocatpy/py.typed +0 -0
  20. package/meteocatpy/stations.py +71 -0
  21. package/meteocatpy/symbols.py +89 -0
  22. package/meteocatpy/town.py +61 -0
  23. package/meteocatpy/townstations.py +99 -0
  24. package/meteocatpy/variables.py +74 -0
  25. package/meteocatpy/version.py +2 -0
  26. package/package.json +23 -0
  27. package/poetry.lock +3313 -0
  28. package/pyproject.toml +72 -0
  29. package/releaserc.json +18 -0
  30. package/requirements.test.txt +3 -0
  31. package/setup.cfg +64 -0
  32. package/setup.py +10 -0
  33. package/tests/data_test.py +122 -0
  34. package/tests/import_test.py +18 -0
  35. package/tests/integration_test_complete.py +77 -0
  36. package/tests/integration_test_forecast.py +54 -0
  37. package/tests/integration_test_station_data.py +34 -0
  38. package/tests/integration_test_stations.py +32 -0
  39. package/tests/integration_test_symbols.py +68 -0
  40. package/tests/integration_test_town.py +32 -0
  41. package/tests/integration_test_town_stations.py +36 -0
  42. package/tests/integration_test_variables.py +32 -0
@@ -0,0 +1,61 @@
1
+ import aiohttp
2
+ from .const import BASE_URL, MUNICIPIS_LIST_URL
3
+ from .exceptions import BadRequestError, ForbiddenError, TooManyRequestsError, InternalServerError, UnknownAPIError
4
+
5
+ class MeteocatTown:
6
+ """Clase para interactuar con la lista de municipios de la API de Meteocat."""
7
+
8
+ def __init__(self, api_key: str):
9
+ """
10
+ Inicializa la clase MeteocatTown.
11
+
12
+ Args:
13
+ api_key (str): Clave de API para autenticar las solicitudes.
14
+ """
15
+ self.api_key = api_key
16
+ self.headers = {
17
+ "Content-Type": "application/json",
18
+ "X-Api-Key": self.api_key,
19
+ }
20
+
21
+ async def get_municipis(self):
22
+ """
23
+ Obtiene la lista de municipios desde la API de Meteocat.
24
+
25
+ Returns:
26
+ dict: Datos de los municipios.
27
+ """
28
+ url = f"{BASE_URL}{MUNICIPIS_LIST_URL}"
29
+ async with aiohttp.ClientSession() as session:
30
+ try:
31
+ async with session.get(url, headers=self.headers) as response:
32
+ if response.status == 200:
33
+ return await response.json()
34
+
35
+ # Gestionar errores según el código de estado
36
+ if response.status == 400:
37
+ raise BadRequestError(await response.json())
38
+ elif response.status == 403:
39
+ error_data = await response.json()
40
+ if error_data.get("message") == "Forbidden":
41
+ raise ForbiddenError(error_data)
42
+ elif error_data.get("message") == "Missing Authentication Token":
43
+ raise ForbiddenError(error_data)
44
+ elif response.status == 429:
45
+ raise TooManyRequestsError(await response.json())
46
+ elif response.status == 500:
47
+ raise InternalServerError(await response.json())
48
+ else:
49
+ raise UnknownAPIError(f"Unexpected error {response.status}: {await response.text()}")
50
+
51
+ except aiohttp.ClientError as e:
52
+ raise UnknownAPIError(
53
+ message=f"Error al conectar con la API de Meteocat: {str(e)}",
54
+ status_code=0,
55
+ )
56
+
57
+ except Exception as ex:
58
+ raise UnknownAPIError(
59
+ message=f"Error inesperado: {str(ex)}",
60
+ status_code=0,
61
+ )
@@ -0,0 +1,99 @@
1
+ import aiohttp
2
+ from .stations import MeteocatStations # Importamos la clase MeteocatStations
3
+ from .const import BASE_URL, STATIONS_MUNICIPI_URL
4
+ from .exceptions import (
5
+ BadRequestError,
6
+ ForbiddenError,
7
+ TooManyRequestsError,
8
+ InternalServerError,
9
+ UnknownAPIError,
10
+ )
11
+
12
+ class MeteocatTownStations:
13
+ """
14
+ Clase para interactuar con la API de Meteocat y obtener
15
+ las estaciones representativas de un municipio para una variable específica.
16
+ """
17
+
18
+ def __init__(self, api_key: str):
19
+ """
20
+ Inicializa la clase MeteocatTownStations.
21
+
22
+ Args:
23
+ api_key (str): Clave de API para autenticar las solicitudes.
24
+ """
25
+ self.api_key = api_key
26
+ self.headers = {
27
+ "Content-Type": "application/json",
28
+ "X-Api-Key": self.api_key,
29
+ }
30
+ self.stations_service = MeteocatStations(api_key) # Instancia de MeteocatStations
31
+
32
+ async def get_town_stations(self, town_id: str, variable_id: str):
33
+ """
34
+ Obtiene la lista de estaciones representativas para un municipio y una variable específica,
35
+ enriqueciendo los datos con el nombre de las estaciones.
36
+
37
+ Args:
38
+ codi_municipi (str): Código del municipio.
39
+ codi_variable (str): Código de la variable.
40
+
41
+ Returns:
42
+ list: Datos de las estaciones representativas con nombres añadidos.
43
+ """
44
+ # Obtener la lista completa de estaciones
45
+ all_stations = await self.stations_service.get_stations()
46
+
47
+ # Crear un diccionario para acceder rápidamente a los nombres por código
48
+ station_names = {station["codi"]: station["nom"] for station in all_stations}
49
+
50
+ # URL para obtener las estaciones del municipio y la variable
51
+ url = f"{BASE_URL}{STATIONS_MUNICIPI_URL}".format(
52
+ codi_municipi=town_id, codi_variable=variable_id
53
+ )
54
+
55
+ async with aiohttp.ClientSession() as session:
56
+ try:
57
+ async with session.get(url, headers=self.headers) as response:
58
+ if response.status == 200:
59
+ data = await response.json()
60
+
61
+ # Enriquecer el JSON con los nombres de las estaciones
62
+ for town in data:
63
+ for variable in town.get("variables", []):
64
+ for station in variable.get("estacions", []):
65
+ codi = station["codi"]
66
+ station["nom"] = station_names.get(codi, "Nombre desconocido")
67
+
68
+ return data
69
+
70
+ # Gestionar errores según el código de estado
71
+ if response.status == 400:
72
+ raise BadRequestError(await response.json())
73
+ elif response.status == 403:
74
+ error_data = await response.json()
75
+ if error_data.get("message") == "Forbidden":
76
+ raise ForbiddenError(error_data)
77
+ elif error_data.get("message") == "Missing Authentication Token":
78
+ raise ForbiddenError(error_data)
79
+ elif response.status == 429:
80
+ raise TooManyRequestsError(await response.json())
81
+ elif response.status == 500:
82
+ raise InternalServerError(await response.json())
83
+ else:
84
+ raise UnknownAPIError(
85
+ f"Unexpected error {response.status}: {await response.text()}"
86
+ )
87
+
88
+ except aiohttp.ClientError as e:
89
+ raise UnknownAPIError(
90
+ message=f"Error al conectar con la API de Meteocat: {str(e)}",
91
+ status_code=0,
92
+ )
93
+
94
+ except Exception as ex:
95
+ raise UnknownAPIError(
96
+ message=f"Error inesperado: {str(ex)}",
97
+ status_code=0,
98
+ )
99
+
@@ -0,0 +1,74 @@
1
+ import aiohttp
2
+ from diskcache import Cache
3
+ from .const import BASE_URL, VARIABLES_URL
4
+ from .exceptions import BadRequestError, ForbiddenError, TooManyRequestsError, InternalServerError, UnknownAPIError
5
+
6
+ class MeteocatVariables:
7
+ """Clase para interactuar con la lista de variables de la API de Meteocat."""
8
+
9
+ _cache = Cache(".meteocat_cache") # Directorio donde se guardará la caché
10
+
11
+ def __init__(self, api_key: str):
12
+ """
13
+ Inicializa la clase MeteocatVariables.
14
+
15
+ Args:
16
+ api_key (str): Clave de API para autenticar las solicitudes.
17
+ """
18
+ self.api_key = api_key
19
+ self.headers = {
20
+ "Content-Type": "application/json",
21
+ "X-Api-Key": self.api_key,
22
+ }
23
+
24
+ async def get_variables(self, force_update=False):
25
+ """
26
+ Obtiene la lista de variables desde la API de Meteocat. Usa la caché si está disponible.
27
+
28
+ Args:
29
+ force_update (bool): Si es True, fuerza la actualización desde la API.
30
+
31
+ Returns:
32
+ list: Datos de las variables.
33
+ """
34
+ # Verificar si las variables están en caché y no se solicita actualización forzada
35
+ if not force_update and "variables" in self._cache:
36
+ return self._cache["variables"]
37
+
38
+ # Hacer la solicitud a la API para obtener las variables
39
+ url = f"{BASE_URL}{VARIABLES_URL}"
40
+ async with aiohttp.ClientSession() as session:
41
+ try:
42
+ async with session.get(url, headers=self.headers) as response:
43
+ if response.status == 200:
44
+ variables = await response.json()
45
+ self._cache["variables"] = variables # Guardar en caché
46
+ return variables
47
+
48
+ # Gestionar errores según el código de estado
49
+ if response.status == 400:
50
+ raise BadRequestError(await response.json())
51
+ elif response.status == 403:
52
+ error_data = await response.json()
53
+ if error_data.get("message") == "Forbidden":
54
+ raise ForbiddenError(error_data)
55
+ elif error_data.get("message") == "Missing Authentication Token":
56
+ raise ForbiddenError(error_data)
57
+ elif response.status == 429:
58
+ raise TooManyRequestsError(await response.json())
59
+ elif response.status == 500:
60
+ raise InternalServerError(await response.json())
61
+ else:
62
+ raise UnknownAPIError(f"Unexpected error {response.status}: {await response.text()}")
63
+
64
+ except aiohttp.ClientError as e:
65
+ raise UnknownAPIError(
66
+ message=f"Error al conectar con la API de Meteocat: {str(e)}",
67
+ status_code=0,
68
+ )
69
+
70
+ except Exception as ex:
71
+ raise UnknownAPIError(
72
+ message=f"Error inesperado: {str(ex)}",
73
+ status_code=0,
74
+ )
@@ -0,0 +1,2 @@
1
+ # version.py
2
+ __version__ = "0.0.7"
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "meteocatpy",
3
+ "version": "0.0.7",
4
+ "description": "[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\r [![Python version compatibility](https://img.shields.io/pypi/pyversions/meteocatpy)](https://pypi.org/project/meteocatpy)\r [![pipeline status](https://gitlab.com/figorr/meteocatpy/badges/master/pipeline.svg)](https://gitlab.com/figorr/meteocatpy/commits/master)",
5
+ "main": "index.js",
6
+ "directories": {
7
+ "example": "examples",
8
+ "test": "tests"
9
+ },
10
+ "scripts": {
11
+ "test": "echo \"Error: no test specified\" && exit 1"
12
+ },
13
+ "keywords": [],
14
+ "author": "",
15
+ "license": "ISC",
16
+ "devDependencies": {
17
+ "@semantic-release/changelog": "^6.0.3",
18
+ "@semantic-release/exec": "^6.0.3",
19
+ "@semantic-release/git": "^10.0.1",
20
+ "@semantic-release/github": "^11.0.1",
21
+ "semantic-release": "^24.2.0"
22
+ }
23
+ }