meteostat 1.7.6__py3-none-any.whl → 2.0.1__py3-none-any.whl
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.
- meteostat/__init__.py +38 -19
- meteostat/api/config.py +158 -0
- meteostat/api/daily.py +76 -0
- meteostat/api/hourly.py +80 -0
- meteostat/api/interpolate.py +378 -0
- meteostat/api/inventory.py +59 -0
- meteostat/api/merge.py +103 -0
- meteostat/api/monthly.py +73 -0
- meteostat/api/normals.py +144 -0
- meteostat/api/point.py +30 -0
- meteostat/api/stations.py +234 -0
- meteostat/api/timeseries.py +334 -0
- meteostat/core/cache.py +212 -59
- meteostat/core/data.py +203 -0
- meteostat/core/logger.py +9 -0
- meteostat/core/network.py +82 -0
- meteostat/core/parameters.py +112 -0
- meteostat/core/providers.py +184 -0
- meteostat/core/schema.py +170 -0
- meteostat/core/validator.py +38 -0
- meteostat/enumerations.py +149 -0
- meteostat/interpolation/idw.py +120 -0
- meteostat/interpolation/lapserate.py +91 -0
- meteostat/interpolation/nearest.py +31 -0
- meteostat/parameters.py +354 -0
- meteostat/providers/dwd/climat.py +166 -0
- meteostat/providers/dwd/daily.py +144 -0
- meteostat/providers/dwd/hourly.py +218 -0
- meteostat/providers/dwd/monthly.py +138 -0
- meteostat/providers/dwd/mosmix.py +351 -0
- meteostat/providers/dwd/poi.py +117 -0
- meteostat/providers/dwd/shared.py +155 -0
- meteostat/providers/eccc/daily.py +87 -0
- meteostat/providers/eccc/hourly.py +104 -0
- meteostat/providers/eccc/monthly.py +66 -0
- meteostat/providers/eccc/shared.py +45 -0
- meteostat/providers/index.py +496 -0
- meteostat/providers/meteostat/daily.py +65 -0
- meteostat/providers/meteostat/daily_derived.py +110 -0
- meteostat/providers/meteostat/hourly.py +66 -0
- meteostat/providers/meteostat/monthly.py +45 -0
- meteostat/providers/meteostat/monthly_derived.py +106 -0
- meteostat/providers/meteostat/shared.py +93 -0
- meteostat/providers/metno/forecast.py +186 -0
- meteostat/providers/noaa/ghcnd.py +228 -0
- meteostat/providers/noaa/isd_lite.py +142 -0
- meteostat/providers/noaa/metar.py +163 -0
- meteostat/typing.py +113 -0
- meteostat/utils/conversions.py +231 -0
- meteostat/utils/data.py +194 -0
- meteostat/utils/geo.py +28 -0
- meteostat/utils/guards.py +51 -0
- meteostat/utils/parsers.py +161 -0
- meteostat/utils/types.py +113 -0
- meteostat/utils/validators.py +31 -0
- meteostat-2.0.1.dist-info/METADATA +130 -0
- meteostat-2.0.1.dist-info/RECORD +64 -0
- {meteostat-1.7.6.dist-info → meteostat-2.0.1.dist-info}/WHEEL +1 -2
- meteostat/core/loader.py +0 -103
- meteostat/core/warn.py +0 -34
- meteostat/enumerations/granularity.py +0 -22
- meteostat/interface/base.py +0 -39
- meteostat/interface/daily.py +0 -118
- meteostat/interface/hourly.py +0 -154
- meteostat/interface/meteodata.py +0 -210
- meteostat/interface/monthly.py +0 -109
- meteostat/interface/normals.py +0 -245
- meteostat/interface/point.py +0 -143
- meteostat/interface/stations.py +0 -252
- meteostat/interface/timeseries.py +0 -237
- meteostat/series/aggregate.py +0 -48
- meteostat/series/convert.py +0 -28
- meteostat/series/count.py +0 -17
- meteostat/series/coverage.py +0 -20
- meteostat/series/fetch.py +0 -28
- meteostat/series/interpolate.py +0 -47
- meteostat/series/normalize.py +0 -76
- meteostat/series/stations.py +0 -22
- meteostat/units.py +0 -149
- meteostat/utilities/__init__.py +0 -0
- meteostat/utilities/aggregations.py +0 -37
- meteostat/utilities/endpoint.py +0 -33
- meteostat/utilities/helpers.py +0 -70
- meteostat/utilities/mutations.py +0 -89
- meteostat/utilities/validations.py +0 -30
- meteostat-1.7.6.dist-info/METADATA +0 -112
- meteostat-1.7.6.dist-info/RECORD +0 -39
- meteostat-1.7.6.dist-info/top_level.txt +0 -1
- /meteostat/{core → api}/__init__.py +0 -0
- /meteostat/{enumerations → interpolation}/__init__.py +0 -0
- /meteostat/{interface → providers}/__init__.py +0 -0
- /meteostat/{interface/interpolate.py → py.typed} +0 -0
- /meteostat/{series → utils}/__init__.py +0 -0
- {meteostat-1.7.6.dist-info → meteostat-2.0.1.dist-info/licenses}/LICENSE +0 -0
meteostat/utils/types.py
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Type parsing utilities
|
|
3
|
+
|
|
4
|
+
This module contains utilities for extracting and validating types
|
|
5
|
+
from class annotations without creating circular imports.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any, Union
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def extract_property_type(cls: type, property_name: str) -> tuple[Any, Any]:
|
|
12
|
+
"""
|
|
13
|
+
Extract the expected type for a class property from type annotations.
|
|
14
|
+
|
|
15
|
+
Parameters
|
|
16
|
+
----------
|
|
17
|
+
cls : type
|
|
18
|
+
The class to extract type information from
|
|
19
|
+
property_name : str
|
|
20
|
+
The name of the property to get the type for
|
|
21
|
+
|
|
22
|
+
Returns
|
|
23
|
+
-------
|
|
24
|
+
tuple[Any, Any]
|
|
25
|
+
A tuple containing (expected_type, original_type) where:
|
|
26
|
+
- expected_type: The actual type to validate against (unwrapped from Optional)
|
|
27
|
+
- original_type: The original type annotation (including Optional wrapper)
|
|
28
|
+
|
|
29
|
+
Raises
|
|
30
|
+
------
|
|
31
|
+
ValueError
|
|
32
|
+
If the property doesn't exist on the class
|
|
33
|
+
"""
|
|
34
|
+
if not hasattr(cls, property_name):
|
|
35
|
+
raise ValueError(f"Property '{property_name}' does not exist")
|
|
36
|
+
|
|
37
|
+
# Get type annotations for the class
|
|
38
|
+
annotations = getattr(cls, "__annotations__", {})
|
|
39
|
+
original_type = annotations.get(property_name)
|
|
40
|
+
|
|
41
|
+
if original_type is None:
|
|
42
|
+
return None, None
|
|
43
|
+
|
|
44
|
+
expected_type = original_type
|
|
45
|
+
|
|
46
|
+
# Handle Optional types (extract the inner type)
|
|
47
|
+
if hasattr(original_type, "__origin__") and original_type.__origin__ is Union:
|
|
48
|
+
args = getattr(original_type, "__args__", ())
|
|
49
|
+
if len(args) == 2 and type(None) in args:
|
|
50
|
+
# This is Optional[Type], extract the non-None type
|
|
51
|
+
# Type narrowing: we know len(args) == 2, so both indices are valid
|
|
52
|
+
arg0 = args[0] # type: ignore
|
|
53
|
+
arg1 = args[1] # type: ignore
|
|
54
|
+
expected_type = arg0 if arg1 is type(None) else arg1
|
|
55
|
+
|
|
56
|
+
return expected_type, original_type
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def validate_parsed_value(
|
|
60
|
+
value: Any, expected_type: Any, original_type: Any, property_name: str
|
|
61
|
+
) -> Any:
|
|
62
|
+
"""
|
|
63
|
+
Validate a parsed value against the expected type and handle special cases.
|
|
64
|
+
|
|
65
|
+
Parameters
|
|
66
|
+
----------
|
|
67
|
+
value : Any
|
|
68
|
+
The parsed value to validate
|
|
69
|
+
expected_type : Any
|
|
70
|
+
The expected type for validation
|
|
71
|
+
original_type : Any
|
|
72
|
+
The original type annotation (for Optional type checking)
|
|
73
|
+
property_name : str
|
|
74
|
+
The name of the property being validated (for error messages)
|
|
75
|
+
|
|
76
|
+
Returns
|
|
77
|
+
-------
|
|
78
|
+
Any
|
|
79
|
+
The validated (and potentially converted) value
|
|
80
|
+
|
|
81
|
+
Raises
|
|
82
|
+
------
|
|
83
|
+
ValueError
|
|
84
|
+
If the value doesn't match the expected type
|
|
85
|
+
"""
|
|
86
|
+
# Check if the parsed value matches the expected type
|
|
87
|
+
if isinstance(value, expected_type):
|
|
88
|
+
return value
|
|
89
|
+
|
|
90
|
+
# Special case for Optional types - None is allowed
|
|
91
|
+
if (
|
|
92
|
+
hasattr(original_type, "__origin__")
|
|
93
|
+
and original_type.__origin__ is Union
|
|
94
|
+
and value is None
|
|
95
|
+
):
|
|
96
|
+
return value
|
|
97
|
+
|
|
98
|
+
# Special case for bool type - allow 0 and 1 to be parsed as False and True
|
|
99
|
+
if expected_type is bool and isinstance(value, int):
|
|
100
|
+
if value == 0:
|
|
101
|
+
return False
|
|
102
|
+
if value == 1:
|
|
103
|
+
return True
|
|
104
|
+
raise ValueError(
|
|
105
|
+
f"Environment variable '{property_name}' has value {value} "
|
|
106
|
+
f"but boolean type only accepts 0, 1, true, or false"
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# Type mismatch
|
|
110
|
+
raise ValueError(
|
|
111
|
+
f"Environment variable '{property_name}' has type {type(value).__name__} "
|
|
112
|
+
f"but expected {expected_type.__name__}"
|
|
113
|
+
)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Validators Module
|
|
3
|
+
|
|
4
|
+
Provides validator functions for data validation.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pandas import Series
|
|
8
|
+
|
|
9
|
+
from meteostat.core.validator import Validator
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def minimum(value: int | float) -> Validator:
|
|
13
|
+
"""
|
|
14
|
+
Numeric minimum
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def _func(series: Series) -> Series:
|
|
18
|
+
return series >= value
|
|
19
|
+
|
|
20
|
+
return Validator(_func)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def maximum(value: int | float) -> Validator:
|
|
24
|
+
"""
|
|
25
|
+
Numeric maximum
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def _func(series: Series) -> Series:
|
|
29
|
+
return series <= value
|
|
30
|
+
|
|
31
|
+
return Validator(_func)
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: meteostat
|
|
3
|
+
Version: 2.0.1
|
|
4
|
+
Summary: Access and analyze historical weather and climate data with Python.
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
Author: Meteostat
|
|
7
|
+
Requires-Python: >=3.11,<4.0
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
13
|
+
Requires-Dist: pandas (>=2.3.3,<3.0.0)
|
|
14
|
+
Requires-Dist: pytz (>=2023.3.post1,<2024.0)
|
|
15
|
+
Requires-Dist: requests (>=2.31.0,<3.0.0)
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
<!-- PROJECT SHIELDS -->
|
|
19
|
+
<div align="center">
|
|
20
|
+
|
|
21
|
+
[![Downloads][downloads-shield]][downloads-url]
|
|
22
|
+
[![Provider Tests][provider-tests-shield]][provider-tests-url]
|
|
23
|
+
[![Issues][issues-shield]][issues-url]
|
|
24
|
+
[![MIT License][license-shield]][license-url]
|
|
25
|
+
[![Stargazers][stars-shield]][stars-url]
|
|
26
|
+
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
<!-- PROJECT LOGO -->
|
|
31
|
+
<br />
|
|
32
|
+
<div align="center">
|
|
33
|
+
<a href="https://github.com/meteostat/meteostat">
|
|
34
|
+
<img src="https://media.meteostat.net/icon.svg" alt="Meteostat Logo" width="80" height="80">
|
|
35
|
+
</a>
|
|
36
|
+
|
|
37
|
+
<h3 align="center">Meteostat Python Package</h3>
|
|
38
|
+
|
|
39
|
+
<p align="center">
|
|
40
|
+
Access and analyze historical weather and climate data with Python.
|
|
41
|
+
<p>
|
|
42
|
+
<a href="https://dev.meteostat.net/python"><strong>Explore the docs »</strong></a>
|
|
43
|
+
</p>
|
|
44
|
+
<p>
|
|
45
|
+
<a href="https://meteostat.net">Visit Website</a>
|
|
46
|
+
·
|
|
47
|
+
<a href="https://github.com/meteostat/meteostat/issues">Report Bug</a>
|
|
48
|
+
·
|
|
49
|
+
<a href="https://github.com/orgs/meteostat/discussions">Request Feature</a>
|
|
50
|
+
</p>
|
|
51
|
+
</p>
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
## 📚 Installation
|
|
55
|
+
|
|
56
|
+
The Meteostat Python package is available through [PyPI](https://pypi.org/project/meteostat/):
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
pip install meteostat
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## 🚀 Usage
|
|
63
|
+
|
|
64
|
+
Let's plot 2018 temperature data for Frankfurt, Germany:
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from datetime import date
|
|
68
|
+
import matplotlib.pyplot as plt
|
|
69
|
+
import meteostat as ms
|
|
70
|
+
|
|
71
|
+
# Specify location and time range
|
|
72
|
+
POINT = ms.Point(50.1155, 8.6842, 113) # Try with your location
|
|
73
|
+
START = date(2018, 1, 1)
|
|
74
|
+
END = date(2018, 12, 31)
|
|
75
|
+
|
|
76
|
+
# Get nearby weather stations
|
|
77
|
+
stations = ms.stations.nearby(POINT, limit=4)
|
|
78
|
+
|
|
79
|
+
# Get daily data & perform interpolation
|
|
80
|
+
ts = ms.daily(stations, START, END)
|
|
81
|
+
df = ms.interpolate(ts, POINT).fetch()
|
|
82
|
+
|
|
83
|
+
# Plot line chart including average, minimum and maximum temperature
|
|
84
|
+
df.plot(y=[ms.Parameter.TEMP, ms.Parameter.TMIN, ms.Parameter.TMAX])
|
|
85
|
+
plt.show()
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Take a look at the expected output:
|
|
89
|
+
|
|
90
|
+
![2018 temperature data for Frankfurt, Germany][product-screenshot]
|
|
91
|
+
|
|
92
|
+
## 🤝 Contributing
|
|
93
|
+
|
|
94
|
+
Please read our [contributing guidelines](https://dev.meteostat.net/python/contributing) for details on how to contribute to the Meteostat Python library.
|
|
95
|
+
|
|
96
|
+
**Top contributors**
|
|
97
|
+
|
|
98
|
+
<a href="https://github.com/meteostat/meteostat/graphs/contributors">
|
|
99
|
+
<img src="https://contrib.rocks/image?repo=meteostat/meteostat" alt="Meteostat Contributors" />
|
|
100
|
+
</a>
|
|
101
|
+
|
|
102
|
+
## 🌟 Featured In
|
|
103
|
+
|
|
104
|
+
Meteostat has been featured and used by various media outlets and organizations, including:
|
|
105
|
+
|
|
106
|
+
- [Towards Data Science](https://towardsdatascience.com/get-temperature-data-by-location-with-python-52ed872dd621/)
|
|
107
|
+
- [ZEIT ONLINE](https://www.zeit.de/digital/internet/2022-03/desinformation-russland-ukraine-fotos-fake-news-falschinformation-echtheit)
|
|
108
|
+
- [Deutsche Presse-Agentur (dpa)](https://dpa-factchecking.com/germany/230103-99-92282/)
|
|
109
|
+
- [heise online](https://www.heise.de/news/Open-Source-Projekt-zu-Klimadaten-Meteostat-Python-Library-1-0-erschienen-4985015.html)
|
|
110
|
+
|
|
111
|
+
Join the growing community of users and researchers relying on Meteostat for their weather data needs.
|
|
112
|
+
|
|
113
|
+
## 📄 License
|
|
114
|
+
|
|
115
|
+
Meteostat is licensed under the [**MIT License**](https://github.com/meteostat/meteostat/blob/main/LICENSE). Data provided by Meteostat is generally licensed under the [**Creative Commons Attribution 4.0 International (CC BY 4.0)**](https://creativecommons.org/licenses/by/4.0) license. Please refer to the [documentation](https://dev.meteostat.net/license) for more information.
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
<!-- MARKDOWN LINKS & IMAGES -->
|
|
119
|
+
<!-- https://www.markdownguide.org/basic-syntax/#reference-style-links -->
|
|
120
|
+
[downloads-shield]: https://img.shields.io/pypi/dm/meteostat
|
|
121
|
+
[downloads-url]: https://pypi.org/project/meteostat/
|
|
122
|
+
[provider-tests-shield]: https://github.com/meteostat/meteostat/actions/workflows/provider-tests.yml/badge.svg
|
|
123
|
+
[provider-tests-url]: https://github.com/meteostat/meteostat/actions/workflows/provider-tests.yml
|
|
124
|
+
[issues-shield]: https://img.shields.io/github/issues/meteostat/meteostat.svg
|
|
125
|
+
[issues-url]: https://github.com/meteostat/meteostat/issues
|
|
126
|
+
[license-shield]: https://img.shields.io/github/license/meteostat/meteostat.svg
|
|
127
|
+
[license-url]: https://github.com/meteostat/meteostat?tab=readme-ov-file#-license
|
|
128
|
+
[product-screenshot]: https://dev.meteostat.net/assets/images/example-8b6cf2a3fe2efa285bc72d7dc72c4865.png
|
|
129
|
+
[stars-shield]: https://img.shields.io/github/stars/meteostat/meteostat.svg
|
|
130
|
+
[stars-url]: https://github.com/meteostat/meteostat/stargazers
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
meteostat/__init__.py,sha256=uoBFnarB7WQtLj61mM-U2FHBq06FLHKLfdSKlTVq7i4,1555
|
|
2
|
+
meteostat/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
meteostat/api/config.py,sha256=DpZ20TLcc7S1uJV_N_SBv2qtVorNgB0hFzX2sHs0tXM,5065
|
|
4
|
+
meteostat/api/daily.py,sha256=SUYxR7HC5Cqyd6cBG42QmSpEP74HwDq5VnqfSznM46Y,2371
|
|
5
|
+
meteostat/api/hourly.py,sha256=KGJ4xBwO__fBrQ5ll5ruLEkrpOCD8bybSBcXJ94-ntE,2556
|
|
6
|
+
meteostat/api/interpolate.py,sha256=6i128g_x5ea3X2Nkn6IlrtPaKqRfakozOcSheTbmxIM,12602
|
|
7
|
+
meteostat/api/inventory.py,sha256=xida9SVdYPm4GpiloVg-zXvkeUi7Egaj_XbxWWhNHuI,1405
|
|
8
|
+
meteostat/api/merge.py,sha256=CtoItPFsRxXWu50g1zjC9q94wTDC6ZzCLhvU3jmZhX4,2638
|
|
9
|
+
meteostat/api/monthly.py,sha256=cZmJiwVNxw5nNNmrx0ohy9bIN_dSt1Nk8crxcCJsJvU,2327
|
|
10
|
+
meteostat/api/normals.py,sha256=3CbRCYrp_mATZwkWbgBphcmLvhoR_hSaDCj0hfsIlKk,5138
|
|
11
|
+
meteostat/api/point.py,sha256=T4fRcf_ozE3O_ywS8lneSfG_dWexk-cNmVHLJKB_idc,718
|
|
12
|
+
meteostat/api/stations.py,sha256=RuS4yhxq-YJ_IOLhXGv-Y3h__8SlkmmtU1BnGUUe9jI,7001
|
|
13
|
+
meteostat/api/timeseries.py,sha256=zwrIT6URl4R4JYEFUDorn5QZg3VRMeKR2XMOF9D9REc,9889
|
|
14
|
+
meteostat/core/cache.py,sha256=Xo6KyExsCw9cRI_6-yJxJIJ9TfQ7x0IMMKarpZb2598,6645
|
|
15
|
+
meteostat/core/data.py,sha256=wnoqgRXeWNVCAcI_SDH-shLGpx_4z5wE6a5ayqbpZnU,5754
|
|
16
|
+
meteostat/core/logger.py,sha256=MUqPTxpw6C9zky4lCeOac9rLjjYkaiHVGVVvLuxKgEg,146
|
|
17
|
+
meteostat/core/network.py,sha256=JGjjWEpJEYJR6Q3NDbOOYdLo9laiValAip5jrxEnzKA,1939
|
|
18
|
+
meteostat/core/parameters.py,sha256=7BJIkFQaxcBRi1yIDgpAYm2VZxBfVPbi5_UdZL9teXE,3288
|
|
19
|
+
meteostat/core/providers.py,sha256=DChq-vILb9uWEcsZmUcUnyeuVGtl3Ote49QhibdeNBo,5490
|
|
20
|
+
meteostat/core/schema.py,sha256=Jbp84bTgWmfhPYhORluGWLEnogevsFiAjwC21Y4Mbwg,5070
|
|
21
|
+
meteostat/core/validator.py,sha256=pJOJIU8FtYO4k7ihGqFxM6CSs9O6oO-fByYyJeJ9pZY,887
|
|
22
|
+
meteostat/enumerations.py,sha256=1lWrnzejtV1uP5CjyeyN-UcYt8wBIqlc5sxwzwh5Rqg,3271
|
|
23
|
+
meteostat/interpolation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
|
+
meteostat/interpolation/idw.py,sha256=AyZWxXjq8mS9BEQtxgSEHQzn7TZYIdkc22kPkF5qZww,4435
|
|
25
|
+
meteostat/interpolation/lapserate.py,sha256=D5Y2DLMgjCNmqfdm2J5MU67w0O6L0vx_TbgMaGrMQuc,2637
|
|
26
|
+
meteostat/interpolation/nearest.py,sha256=xZg_6OCvU8uI-i7UbPQHjsJmtlz_DbZqrDz00dJthEM,782
|
|
27
|
+
meteostat/parameters.py,sha256=w7G3ktLVasAbaR9OnjuMAvrq_c1zLz5PVt3zofDFun4,10074
|
|
28
|
+
meteostat/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
|
+
meteostat/providers/dwd/climat.py,sha256=jEHvg9m8L0161n1j7DHOiBWyky7WL0SD-TrlkljoYCI,4875
|
|
30
|
+
meteostat/providers/dwd/daily.py,sha256=qVZjMUu6a1GODaWrKpzbOYdXS9HyEkKp9XwnY47Md44,4030
|
|
31
|
+
meteostat/providers/dwd/hourly.py,sha256=LAjnQJrp80wOhX24JwuceAtCi104DC8EDwEZetHDrso,6249
|
|
32
|
+
meteostat/providers/dwd/monthly.py,sha256=JaXklCJrH_xlQPm1G6PXoVvV81qwnhT2o1mXXEzM2LQ,3658
|
|
33
|
+
meteostat/providers/dwd/mosmix.py,sha256=uDalWL-_Vayyq3iiiCUWPFmKXSYqQttXiDOF2Lk_qB4,8892
|
|
34
|
+
meteostat/providers/dwd/poi.py,sha256=Qv4eDsi_a8hdBQKl1LPQJ0BO2UbTxfba9gH5Ht2giZ0,3087
|
|
35
|
+
meteostat/providers/dwd/shared.py,sha256=z4LT0fd7LFUqpVPJRJyNWJxK_6TRzJFDvolv6_Y9PME,2917
|
|
36
|
+
meteostat/providers/eccc/daily.py,sha256=K-akr9JXYMnsdG1YlM9SPXUcDfVzv61KsCqD9Ieo6YM,2722
|
|
37
|
+
meteostat/providers/eccc/hourly.py,sha256=W2qMX0HxffMs1IlBzKY4b0M58wPJvtDw7Py4xyDuNO8,3209
|
|
38
|
+
meteostat/providers/eccc/monthly.py,sha256=eA5JRpDa7-2H-Ce4FOstY24ECWj_gTY5vRbvZa_LCLE,1805
|
|
39
|
+
meteostat/providers/eccc/shared.py,sha256=2m00uWYdWQrVqvxwMioLIKFxlrjLmCfqIYwjx30r_9k,1324
|
|
40
|
+
meteostat/providers/index.py,sha256=6UrzxtynwbILOxg_lmE_Ylh747GZzDW_6ytGIEQHTNc,12670
|
|
41
|
+
meteostat/providers/meteostat/daily.py,sha256=32vh0J5caMT9gshfUBQXoH8CB3r3qf4BUlB3VztvPN0,1795
|
|
42
|
+
meteostat/providers/meteostat/daily_derived.py,sha256=_fiLSKxkaH9Caxp-Tg77rH39UXwy7SPDlCS_M-7kIqE,3170
|
|
43
|
+
meteostat/providers/meteostat/hourly.py,sha256=INO5JVaDbd3zIEo3_spIwACoBpYqDXinyrL-pW1AIAk,1798
|
|
44
|
+
meteostat/providers/meteostat/monthly.py,sha256=4N2ThwBroQVz2wI5UI2WpvIUGOH61gS63rP8ZVaMqOE,1253
|
|
45
|
+
meteostat/providers/meteostat/monthly_derived.py,sha256=8BNSd2-xqABdr3lDU_9noypF91qhRJPhz5liTK0eoR8,3075
|
|
46
|
+
meteostat/providers/meteostat/shared.py,sha256=mK2K3tbgtCcKLMITR5NJVuJSBkPm_jLcN0dBRT9hM90,2571
|
|
47
|
+
meteostat/providers/metno/forecast.py,sha256=x-q21HiGkJ4yiv7vKcPnVSFin3rFGHWAZqtzJE0j4Tk,5661
|
|
48
|
+
meteostat/providers/noaa/ghcnd.py,sha256=AaR-efQkbgc3afwcvMd_H25_l1dV5CFmautn9TWQ6Cw,6789
|
|
49
|
+
meteostat/providers/noaa/isd_lite.py,sha256=YfqhWJjNjxirbqeGaRsQo07koEREvY-APVETkZ3eBKM,3817
|
|
50
|
+
meteostat/providers/noaa/metar.py,sha256=wqH0zEUZO0gS0inK5vvxKulz-LF3NEZIAsYHmR0Do64,4188
|
|
51
|
+
meteostat/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
52
|
+
meteostat/typing.py,sha256=Q4_le4P_yOVyv1FAxtccNDfFc0OPzYKm3p-GTTptGAY,3504
|
|
53
|
+
meteostat/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
54
|
+
meteostat/utils/conversions.py,sha256=B1qaL3_OSbWniIsFCwDPnwWtmglRiBBswFK1q0NH4bI,4755
|
|
55
|
+
meteostat/utils/data.py,sha256=d_aQy53jdhDAvFvo0qVPyhR2NH-WKIAeNm_kIobJOq8,6119
|
|
56
|
+
meteostat/utils/geo.py,sha256=n_imXze6-u0vzFdYrgPyStKqGNuERcUmXUA-PsAja2w,664
|
|
57
|
+
meteostat/utils/guards.py,sha256=fuBd4_6BXfZT_jPYU6GzXgDBnCc_GVLDpI6PSK3PCno,1746
|
|
58
|
+
meteostat/utils/parsers.py,sha256=2y-QSubyrh_xdXJBdgWNiWNI_DDXCGxddcjGOZB9hCU,4646
|
|
59
|
+
meteostat/utils/types.py,sha256=_hzGcVueIGZdjCB6mR4vVFedrPUWw0iMRaLkpnqaN2Y,3470
|
|
60
|
+
meteostat/utils/validators.py,sha256=iBywF68ZhL3eD6fgemY2Tng3a-409eFU2oNZVqpYCpY,524
|
|
61
|
+
meteostat-2.0.1.dist-info/METADATA,sha256=cAXHfPnAXC-3gEpeUMfmRqURQWjOufDsXHfX_fjm650,5024
|
|
62
|
+
meteostat-2.0.1.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
63
|
+
meteostat-2.0.1.dist-info/licenses/LICENSE,sha256=kqpl7FVzWOCe11BZqJBZ1aRQi-aK87j3ljtG7P3VxLc,1066
|
|
64
|
+
meteostat-2.0.1.dist-info/RECORD,,
|
meteostat/core/loader.py
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Core Class - Data Loader
|
|
3
|
-
|
|
4
|
-
Meteorological data provided by Meteostat (https://dev.meteostat.net)
|
|
5
|
-
under the terms of the Creative Commons Attribution-NonCommercial
|
|
6
|
-
4.0 International Public License.
|
|
7
|
-
|
|
8
|
-
The code is licensed under the MIT license.
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
from io import BytesIO
|
|
12
|
-
from gzip import GzipFile
|
|
13
|
-
from urllib.request import Request, ProxyHandler, build_opener
|
|
14
|
-
from urllib.error import HTTPError
|
|
15
|
-
from multiprocessing import Pool
|
|
16
|
-
from multiprocessing.pool import ThreadPool
|
|
17
|
-
from typing import Callable, List, Optional
|
|
18
|
-
import pandas as pd
|
|
19
|
-
from meteostat.core.warn import warn
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def processing_handler(
|
|
23
|
-
datasets: List, load: Callable[[dict], None], cores: int, threads: int
|
|
24
|
-
) -> None:
|
|
25
|
-
"""
|
|
26
|
-
Load multiple datasets (simultaneously)
|
|
27
|
-
"""
|
|
28
|
-
|
|
29
|
-
# Data output
|
|
30
|
-
output = []
|
|
31
|
-
|
|
32
|
-
# Multi-core processing
|
|
33
|
-
if cores > 1 and len(datasets) > 1:
|
|
34
|
-
# Create process pool
|
|
35
|
-
with Pool(cores) as pool:
|
|
36
|
-
# Process datasets in pool
|
|
37
|
-
output = pool.starmap(load, datasets)
|
|
38
|
-
|
|
39
|
-
# Wait for Pool to finish
|
|
40
|
-
pool.close()
|
|
41
|
-
pool.join()
|
|
42
|
-
|
|
43
|
-
# Multi-thread processing
|
|
44
|
-
elif threads > 1 and len(datasets) > 1:
|
|
45
|
-
# Create process pool
|
|
46
|
-
with ThreadPool(threads) as pool:
|
|
47
|
-
# Process datasets in pool
|
|
48
|
-
output = pool.starmap(load, datasets)
|
|
49
|
-
|
|
50
|
-
# Wait for Pool to finish
|
|
51
|
-
pool.close()
|
|
52
|
-
pool.join()
|
|
53
|
-
|
|
54
|
-
# Single-thread processing
|
|
55
|
-
else:
|
|
56
|
-
for dataset in datasets:
|
|
57
|
-
output.append(load(*dataset))
|
|
58
|
-
|
|
59
|
-
# Remove empty DataFrames
|
|
60
|
-
filtered = list(filter(lambda df: not df.empty, output))
|
|
61
|
-
|
|
62
|
-
return pd.concat(filtered) if len(filtered) > 0 else output[0]
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def load_handler(
|
|
66
|
-
endpoint: str,
|
|
67
|
-
path: str,
|
|
68
|
-
proxy: Optional[str] = None,
|
|
69
|
-
names: Optional[List] = None,
|
|
70
|
-
dtype: Optional[dict] = None,
|
|
71
|
-
parse_dates: Optional[List] = None,
|
|
72
|
-
default_df: Optional[pd.DataFrame] = None,
|
|
73
|
-
) -> pd.DataFrame:
|
|
74
|
-
"""
|
|
75
|
-
Load a single CSV file into a DataFrame
|
|
76
|
-
"""
|
|
77
|
-
|
|
78
|
-
try:
|
|
79
|
-
handlers = []
|
|
80
|
-
|
|
81
|
-
# Set a proxy
|
|
82
|
-
if proxy:
|
|
83
|
-
handlers.append(ProxyHandler({"http": proxy, "https": proxy}))
|
|
84
|
-
|
|
85
|
-
# Read CSV file from Meteostat endpoint
|
|
86
|
-
with build_opener(*handlers).open(Request(endpoint + path)) as response:
|
|
87
|
-
# Decompress the content
|
|
88
|
-
with GzipFile(fileobj=BytesIO(response.read()), mode="rb") as file:
|
|
89
|
-
df = pd.read_csv(
|
|
90
|
-
file,
|
|
91
|
-
names=names,
|
|
92
|
-
dtype=dtype,
|
|
93
|
-
parse_dates=parse_dates,
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
except (FileNotFoundError, HTTPError):
|
|
97
|
-
df = default_df if default_df is not None else pd.DataFrame(columns=names)
|
|
98
|
-
|
|
99
|
-
# Display warning
|
|
100
|
-
warn(f"Cannot load {path} from {endpoint}")
|
|
101
|
-
|
|
102
|
-
# Return DataFrame
|
|
103
|
-
return df
|
meteostat/core/warn.py
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Core Class - Warnings
|
|
3
|
-
|
|
4
|
-
Meteorological data provided by Meteostat (https://dev.meteostat.net)
|
|
5
|
-
under the terms of the Creative Commons Attribution-NonCommercial
|
|
6
|
-
4.0 International Public License.
|
|
7
|
-
|
|
8
|
-
The code is licensed under the MIT license.
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
import warnings
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def _format(message, category, _filename, _lineno, _line=None) -> str:
|
|
15
|
-
"""
|
|
16
|
-
Print warning on a single line
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
return f"{category.__name__}: {message}\n"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
# Set warning format
|
|
23
|
-
warnings.formatwarning = _format
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def warn(message: str) -> None:
|
|
27
|
-
"""
|
|
28
|
-
Create a warning
|
|
29
|
-
"""
|
|
30
|
-
|
|
31
|
-
try:
|
|
32
|
-
warnings.warn(message, Warning)
|
|
33
|
-
except TypeError:
|
|
34
|
-
pass
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Granularity Enumeration
|
|
3
|
-
|
|
4
|
-
Meteorological data provided by Meteostat (https://dev.meteostat.net)
|
|
5
|
-
under the terms of the Creative Commons Attribution-NonCommercial
|
|
6
|
-
4.0 International Public License.
|
|
7
|
-
|
|
8
|
-
The code is licensed under the MIT license.
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
from enum import Enum
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class Granularity(Enum):
|
|
15
|
-
"""
|
|
16
|
-
The different levels of time series granularity
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
HOURLY = "hourly"
|
|
20
|
-
DAILY = "daily"
|
|
21
|
-
MONTHLY = "monthly"
|
|
22
|
-
NORMALS = "normals"
|
meteostat/interface/base.py
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Base Interface Class
|
|
3
|
-
|
|
4
|
-
Meteorological data provided by Meteostat (https://dev.meteostat.net)
|
|
5
|
-
under the terms of the Creative Commons Attribution-NonCommercial
|
|
6
|
-
4.0 International Public License.
|
|
7
|
-
|
|
8
|
-
The code is licensed under the MIT license.
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
import os
|
|
12
|
-
from typing import Optional
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class Base:
|
|
16
|
-
"""
|
|
17
|
-
Base class that provides features which are used across the package
|
|
18
|
-
"""
|
|
19
|
-
|
|
20
|
-
# Base URL of the Meteostat bulk data interface
|
|
21
|
-
endpoint = "https://bulk.meteostat.net/v2/"
|
|
22
|
-
|
|
23
|
-
# Proxy URL for the Meteostat (bulk) data interface
|
|
24
|
-
proxy: Optional[str] = None
|
|
25
|
-
|
|
26
|
-
# Location of the cache directory
|
|
27
|
-
cache_dir = os.path.expanduser("~") + os.sep + ".meteostat" + os.sep + "cache"
|
|
28
|
-
|
|
29
|
-
# Auto clean cache directories?
|
|
30
|
-
autoclean = True
|
|
31
|
-
|
|
32
|
-
# Maximum age of a cached file in seconds
|
|
33
|
-
max_age = 24 * 60 * 60
|
|
34
|
-
|
|
35
|
-
# Number of processes used for processing files
|
|
36
|
-
processes = 1
|
|
37
|
-
|
|
38
|
-
# Number of threads used for processing files
|
|
39
|
-
threads = 1
|
meteostat/interface/daily.py
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Daily Class
|
|
3
|
-
|
|
4
|
-
Meteorological data provided by Meteostat (https://dev.meteostat.net)
|
|
5
|
-
under the terms of the Creative Commons Attribution-NonCommercial
|
|
6
|
-
4.0 International Public License.
|
|
7
|
-
|
|
8
|
-
The code is licensed under the MIT license.
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
from datetime import datetime, timedelta
|
|
12
|
-
from typing import Union
|
|
13
|
-
import pandas as pd
|
|
14
|
-
from meteostat.enumerations.granularity import Granularity
|
|
15
|
-
from meteostat.utilities.aggregations import degree_mean
|
|
16
|
-
from meteostat.interface.timeseries import TimeSeries
|
|
17
|
-
from meteostat.interface.point import Point
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class Daily(TimeSeries):
|
|
21
|
-
"""
|
|
22
|
-
Retrieve daily weather observations for one or multiple weather stations or
|
|
23
|
-
a single geographical point
|
|
24
|
-
"""
|
|
25
|
-
|
|
26
|
-
# The cache subdirectory
|
|
27
|
-
cache_subdir = "daily"
|
|
28
|
-
|
|
29
|
-
# Granularity
|
|
30
|
-
granularity = Granularity.DAILY
|
|
31
|
-
|
|
32
|
-
# Download data as annual chunks
|
|
33
|
-
# This cannot be changed and is only kept for backward compatibility
|
|
34
|
-
chunked = True
|
|
35
|
-
|
|
36
|
-
# Default frequency
|
|
37
|
-
_freq = "1D"
|
|
38
|
-
|
|
39
|
-
# Source mappings
|
|
40
|
-
_source_mappings = {
|
|
41
|
-
"dwd_daily": "A",
|
|
42
|
-
"eccc_daily": "A",
|
|
43
|
-
"ghcnd": "B",
|
|
44
|
-
"dwd_hourly": "C",
|
|
45
|
-
"eccc_hourly": "C",
|
|
46
|
-
"isd_lite": "D",
|
|
47
|
-
"synop": "E",
|
|
48
|
-
"dwd_poi": "E",
|
|
49
|
-
"metar": "F",
|
|
50
|
-
"model": "G",
|
|
51
|
-
"dwd_mosmix": "G",
|
|
52
|
-
"metno_forecast": "G",
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
# Flag which represents model data
|
|
56
|
-
_model_flag = "G"
|
|
57
|
-
|
|
58
|
-
# Columns
|
|
59
|
-
_columns = [
|
|
60
|
-
"year",
|
|
61
|
-
"month",
|
|
62
|
-
"day",
|
|
63
|
-
{"tavg": "temp"},
|
|
64
|
-
"tmin",
|
|
65
|
-
"tmax",
|
|
66
|
-
"prcp",
|
|
67
|
-
{"snow": "snwd"},
|
|
68
|
-
{"wdir": None},
|
|
69
|
-
"wspd",
|
|
70
|
-
"wpgt",
|
|
71
|
-
"pres",
|
|
72
|
-
"tsun",
|
|
73
|
-
]
|
|
74
|
-
|
|
75
|
-
# Index of first meteorological column
|
|
76
|
-
_first_met_col = 3
|
|
77
|
-
|
|
78
|
-
# Columns for date parsing
|
|
79
|
-
_parse_dates = ["year", "month", "day"]
|
|
80
|
-
|
|
81
|
-
# Default aggregation functions
|
|
82
|
-
aggregations = {
|
|
83
|
-
"tavg": "mean",
|
|
84
|
-
"tmin": "min",
|
|
85
|
-
"tmax": "max",
|
|
86
|
-
"prcp": "sum",
|
|
87
|
-
"snow": "max",
|
|
88
|
-
"wdir": degree_mean,
|
|
89
|
-
"wspd": "mean",
|
|
90
|
-
"wpgt": "max",
|
|
91
|
-
"pres": "mean",
|
|
92
|
-
"tsun": "sum",
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
def __init__(
|
|
96
|
-
self,
|
|
97
|
-
loc: Union[pd.DataFrame, Point, list, str], # Station(s) or geo point
|
|
98
|
-
start=datetime(1781, 1, 1, 0, 0, 0),
|
|
99
|
-
end=datetime.combine(
|
|
100
|
-
datetime.today().date() + timedelta(days=10), datetime.max.time()
|
|
101
|
-
),
|
|
102
|
-
model=True, # Include model data?
|
|
103
|
-
flags=False, # Load source flags?
|
|
104
|
-
) -> None:
|
|
105
|
-
# Extract relevant years
|
|
106
|
-
if self.chunked:
|
|
107
|
-
self._annual_steps = [
|
|
108
|
-
start.year + i for i in range(end.year - start.year + 1)
|
|
109
|
-
]
|
|
110
|
-
# Initialize time series
|
|
111
|
-
self._init_time_series(loc, start, end, model, flags)
|
|
112
|
-
|
|
113
|
-
def expected_rows(self) -> int:
|
|
114
|
-
"""
|
|
115
|
-
Return the number of rows expected for the defined date range
|
|
116
|
-
"""
|
|
117
|
-
|
|
118
|
-
return (self._end - self._start).days + 1
|