Skip to content

Commit 1508985

Browse files
clamprIntergalactycCopilotCopilot
authored
Release 1.7.5 (#207)
* Fix to timeseries creation of flag columns to handle case where column exists without its flag analog (#204) * fix: AttributeError when no weather stations are found near a location (#206) * Initial plan * Add tests to reproduce _types AttributeError Co-authored-by: clampr <[email protected]> * Fix AttributeError when no weather stations are found Co-authored-by: clampr <[email protected]> * Fix linting issues in test file Co-authored-by: clampr <[email protected]> * fix: fix linter issues * fix: normals tavg calculation on empty df --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: clampr <[email protected]> Co-authored-by: clampr <[email protected]> * chore: bump version * Update meteostat/interface/normals.py Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Intergalactyc <[email protected]> Co-authored-by: Copilot <[email protected]> Co-authored-by: clampr <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent 3f5acc3 commit 1508985

File tree

7 files changed

+103
-6
lines changed

7 files changed

+103
-6
lines changed

meteostat/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"""
1313

1414
__appname__ = "meteostat"
15-
__version__ = "1.7.4"
15+
__version__ = "1.7.5"
1616

1717
from .interface.base import Base
1818
from .interface.timeseries import TimeSeries

meteostat/interface/meteodata.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ def _get_data(self) -> None:
118118
)
119119

120120
# Empty DataFrame
121-
return pd.DataFrame(columns=[*self._types])
121+
return pd.DataFrame(columns=self._processed_columns)
122122

123123
# pylint: disable=too-many-branches
124124
def _resolve_point(

meteostat/interface/normals.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,12 @@ def fetch(self) -> pd.DataFrame:
219219

220220
# Add avg. temperature column
221221
temp.insert(
222-
0, "tavg", temp[["tmin", "tmax"]].dropna(how="any").mean(axis=1).round(1)
222+
0,
223+
"tavg",
224+
pd.to_numeric(
225+
temp[["tmin", "tmax"]].dropna(how="any").mean(axis=1),
226+
errors="coerce"
227+
).round(1)
223228
)
224229

225230
# Remove station index if it's a single station

meteostat/interface/timeseries.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,9 @@ def _init_time_series(
194194
if col not in self._data.columns:
195195
self._data[col] = pd.NA
196196
self._data[col] = self._data[col].astype("Float64")
197-
self._data[f"{col}_flag"] = pd.NA
198-
self._data[f"{col}_flag"] = self._data[f"{col}_flag"].astype("string")
197+
if (flagcol := f"{col}_flag") not in self._data.columns:
198+
self._data[flagcol] = pd.NA
199+
self._data[flagcol] = self._data[flagcol].astype("string")
199200

200201
# Reorder the DataFrame
201202
self._data = self._data[

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# Setup
1616
setup(
1717
name="meteostat",
18-
version="1.7.4",
18+
version="1.7.5",
1919
author="Meteostat",
2020
author_email="[email protected]",
2121
description="Access and analyze historical weather and climate data with Python.",

tests/unit/interface/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Unit test init"""
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
"""
2+
Unit Test - MeteoData with no stations
3+
4+
Tests the fix for the issue where an AttributeError occurs
5+
when no weather stations are found near a location.
6+
7+
The code is licensed under the MIT license.
8+
"""
9+
10+
from datetime import datetime
11+
import pandas as pd
12+
from meteostat import Monthly, Hourly, Daily, Normals
13+
14+
15+
def test_monthly_no_stations():
16+
"""
17+
Test: Monthly class with no stations found (simulated via empty station list)
18+
"""
19+
# Create an empty DataFrame with station columns
20+
empty_stations = pd.DataFrame(columns=["id", "latitude", "longitude", "elevation"])
21+
empty_stations = empty_stations.set_index("id")
22+
23+
# This should not raise AttributeError: 'Monthly' object has no attribute '_types'
24+
try:
25+
data = Monthly(empty_stations, start=datetime(2024, 1, 1), end=datetime(2024, 12, 31))
26+
df = data.fetch()
27+
# Should return an empty DataFrame with the correct columns
28+
assert isinstance(df, pd.DataFrame)
29+
assert len(df) == 0
30+
except AttributeError as exception:
31+
if "'Monthly' object has no attribute '_types'" in str(exception):
32+
raise AssertionError(f"Bug still present: {exception}") from exception
33+
raise
34+
35+
36+
def test_hourly_no_stations():
37+
"""
38+
Test: Hourly class with no stations found
39+
"""
40+
empty_stations = pd.DataFrame(columns=["id", "latitude", "longitude", "elevation"])
41+
empty_stations = empty_stations.set_index("id")
42+
43+
try:
44+
data = Hourly(empty_stations, start=datetime(2024, 1, 1, 0), end=datetime(2024, 1, 1, 23))
45+
df = data.fetch()
46+
assert isinstance(df, pd.DataFrame)
47+
assert len(df) == 0
48+
except AttributeError as exception:
49+
if "'Hourly' object has no attribute '_types'" in str(exception):
50+
raise AssertionError(f"Bug still present: {exception}") from exception
51+
raise
52+
53+
54+
def test_daily_no_stations():
55+
"""
56+
Test: Daily class with no stations found
57+
"""
58+
empty_stations = pd.DataFrame(columns=["id", "latitude", "longitude", "elevation"])
59+
empty_stations = empty_stations.set_index("id")
60+
61+
try:
62+
data = Daily(empty_stations, start=datetime(2024, 1, 1), end=datetime(2024, 1, 31))
63+
df = data.fetch()
64+
assert isinstance(df, pd.DataFrame)
65+
assert len(df) == 0
66+
except AttributeError as exception:
67+
if "'Daily' object has no attribute '_types'" in str(exception):
68+
raise AssertionError(f"Bug still present: {exception}") from exception
69+
raise
70+
71+
72+
def test_normals_no_stations():
73+
"""
74+
Test: Normals class with no stations found
75+
"""
76+
empty_stations = pd.DataFrame(columns=["id", "latitude", "longitude", "elevation"])
77+
empty_stations = empty_stations.set_index("id")
78+
79+
try:
80+
# The main bug fix: creating Normals with no stations
81+
# should not raise AttributeError
82+
data = Normals(empty_stations, start=1991, end=2020)
83+
# Check that data object was created successfully
84+
assert isinstance(data, Normals)
85+
assert len(data._stations) == 0
86+
assert data.count() == 0
87+
except AttributeError as exception:
88+
if "'Normals' object has no attribute '_types'" in str(exception):
89+
raise AssertionError(f"Bug still present: {exception}") from exception
90+
raise

0 commit comments

Comments
 (0)