grib2sail 0.2.0__py3-none-any.whl → 0.3.0__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.
- grib2sail/_version.py +2 -2
- grib2sail/cli.py +15 -11
- grib2sail/downloader.py +21 -5
- grib2sail/downloader_arom.py +12 -21
- grib2sail/downloader_gfs.py +68 -0
- grib2sail/variables.py +1 -1
- grib2sail/variables_arom.py +10 -0
- grib2sail/variables_gfs.py +11 -0
- {grib2sail-0.2.0.dist-info → grib2sail-0.3.0.dist-info}/METADATA +20 -9
- grib2sail-0.3.0.dist-info/RECORD +17 -0
- grib2sail-0.2.0.dist-info/RECORD +0 -15
- {grib2sail-0.2.0.dist-info → grib2sail-0.3.0.dist-info}/WHEEL +0 -0
- {grib2sail-0.2.0.dist-info → grib2sail-0.3.0.dist-info}/licenses/LICENSE +0 -0
- {grib2sail-0.2.0.dist-info → grib2sail-0.3.0.dist-info}/top_level.txt +0 -0
grib2sail/_version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.
|
|
32
|
-
__version_tuple__ = version_tuple = (0,
|
|
31
|
+
__version__ = version = '0.3.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 3, 0)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
grib2sail/cli.py
CHANGED
|
@@ -10,9 +10,10 @@ app = typer.Typer(help='Download GRIB2 meteorological data')
|
|
|
10
10
|
# main cli entry point
|
|
11
11
|
@app.command()
|
|
12
12
|
def main(
|
|
13
|
-
model: str = typer.Option(v.MODELS[0], help='
|
|
14
|
-
step: str = typer.Option(v.STEPS[1], help='
|
|
15
|
-
|
|
13
|
+
model: str = typer.Option(v.MODELS[0], help='Choose one among: ' + ', '.join(v.MODELS)),
|
|
14
|
+
step: str = typer.Option(v.STEPS[1], help='Choose one among: ' + ', '.join(v.STEPS)),
|
|
15
|
+
days: str = typer.Option(2, help='Forecast duration in days'),
|
|
16
|
+
data: str = typer.Option(v.DATAS[0], help='Choose multiple among: ' + ', '.join(v.DATAS)),
|
|
16
17
|
lat: str = typer.Option(..., help='latitudes max and min ex: -7,-2'),
|
|
17
18
|
lon: str = typer.Option(..., help='longitude max and min ex: -62,-60'),
|
|
18
19
|
debug: bool = typer.Option(False, help='Enable debug prints'),
|
|
@@ -24,11 +25,10 @@ def main(
|
|
|
24
25
|
logger.debug(f"latitude is now: {lat}")
|
|
25
26
|
lon = parse_coord(lon)
|
|
26
27
|
logger.debug(f"longitude is now: {lon}")
|
|
27
|
-
validate_input(model, step, data, lat, lon)
|
|
28
|
-
|
|
29
|
-
logger.debug(f"model: {model}, step: {step}, data: {data}")
|
|
28
|
+
validate_input(model, step, days, data, lat, lon)
|
|
29
|
+
logger.debug(f"model: {model}, step: {step}, days: {days}, data: {data}")
|
|
30
30
|
logger.info(f"Downloading from {model}: {data}")
|
|
31
|
-
download_gribs(model, step, data, lat, lon)
|
|
31
|
+
download_gribs(model, step, days, data, lat, lon)
|
|
32
32
|
logger.info('Done')
|
|
33
33
|
|
|
34
34
|
## HELPER FUNCTIONS
|
|
@@ -49,12 +49,16 @@ def convert_to_nb(nb_str):
|
|
|
49
49
|
msg = f"failed to convert to int or float: {nb_str}"
|
|
50
50
|
raise typer.BadParameter(msg)
|
|
51
51
|
|
|
52
|
-
def validate_input(
|
|
53
|
-
if
|
|
52
|
+
def validate_input(model, step, days, data, lat, lon):
|
|
53
|
+
if model not in v.MODELS:
|
|
54
54
|
logger.error_exit('model must be one of: ' + '|'.join(v.MODELS))
|
|
55
|
-
if
|
|
55
|
+
if step not in v.STEPS:
|
|
56
56
|
logger.error_exit('step must be one of: ' + '|'.join(v.STEPS))
|
|
57
|
-
|
|
57
|
+
try:
|
|
58
|
+
int(days)
|
|
59
|
+
except ValueError:
|
|
60
|
+
logger.error_exit('days must be an integer, ex --days 4')
|
|
61
|
+
for elmnt in data:
|
|
58
62
|
if elmnt not in v.DATAS:
|
|
59
63
|
msg = 'data must be a combinaison of: '
|
|
60
64
|
logger.error_exit(msg + ','.join(v.DATAS))
|
grib2sail/downloader.py
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
2
2
|
import threading
|
|
3
3
|
import requests
|
|
4
|
+
from pathlib import Path
|
|
4
5
|
from rich.progress import Progress
|
|
5
6
|
|
|
6
7
|
from grib2sail.logger import logger
|
|
7
8
|
from grib2sail.downloader_arom import handle_fetch_error_arom, download_arom
|
|
9
|
+
from grib2sail.downloader_gfs import download_gfs
|
|
8
10
|
import grib2sail.variables as v
|
|
9
11
|
|
|
10
12
|
thread_local = threading.local()
|
|
@@ -14,13 +16,16 @@ def get_session():
|
|
|
14
16
|
thread_local.session = requests.Session()
|
|
15
17
|
return thread_local.session
|
|
16
18
|
|
|
17
|
-
def download_gribs(
|
|
18
|
-
if
|
|
19
|
-
download_arom(
|
|
19
|
+
def download_gribs(model, step, days, data, lat, lon):
|
|
20
|
+
if model.startswith('arome'):
|
|
21
|
+
download_arom(model, step, days, data, lat, lon)
|
|
22
|
+
elif model == 'gfs':
|
|
23
|
+
download_gfs(model, step, days, data, lat, lon)
|
|
20
24
|
else:
|
|
21
|
-
logger.error_exit(f"Downloader failed: unexpected model: {
|
|
25
|
+
logger.error_exit(f"Downloader failed: unexpected model: {model}")
|
|
22
26
|
|
|
23
|
-
|
|
27
|
+
# Optimized resource fetcher with threading and common session
|
|
28
|
+
def get_layers(model, urls, header={}):
|
|
24
29
|
# Downloading every layers
|
|
25
30
|
layers = [None] * len(urls)
|
|
26
31
|
with Progress() as progress:
|
|
@@ -40,6 +45,7 @@ def get_layers(model, urls, header):
|
|
|
40
45
|
progress.advance(task)
|
|
41
46
|
return layers
|
|
42
47
|
|
|
48
|
+
# Fetch an url and handle errors differently depending on the model
|
|
43
49
|
def fetch(idx, url, headers, model):
|
|
44
50
|
try:
|
|
45
51
|
session = get_session()
|
|
@@ -52,3 +58,13 @@ def fetch(idx, url, headers, model):
|
|
|
52
58
|
else:
|
|
53
59
|
logger.error_exit(f"Download failed: {e}")
|
|
54
60
|
return idx, None
|
|
61
|
+
|
|
62
|
+
# Output the file once all the layers have been downloaded
|
|
63
|
+
def write_file(model, run, step, layers):
|
|
64
|
+
file = Path(f"{model}_{run}_{step}.grib2")
|
|
65
|
+
file.unlink(missing_ok=True)
|
|
66
|
+
with open(file, "wb") as outfile:
|
|
67
|
+
for layer in layers:
|
|
68
|
+
if layer:
|
|
69
|
+
outfile.write(layer)
|
|
70
|
+
|
grib2sail/downloader_arom.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
from pathlib import Path
|
|
2
1
|
import re
|
|
3
2
|
import requests
|
|
4
3
|
import time as t
|
|
@@ -9,20 +8,16 @@ import grib2sail.downloader as d
|
|
|
9
8
|
from grib2sail.logger import logger
|
|
10
9
|
from grib2sail.token import get_arome_token
|
|
11
10
|
|
|
12
|
-
def download_arom(model, step, data, lat, lon):
|
|
11
|
+
def download_arom(model, step, days, data, lat, lon):
|
|
13
12
|
token = get_arome_token()
|
|
14
|
-
|
|
15
13
|
# Coverages list all the individual layers categories to download
|
|
16
14
|
coverages = []
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if v.DATAS[3] in data:
|
|
24
|
-
coverages += [va.AROM_DATAS['cloud']]
|
|
25
|
-
|
|
15
|
+
for param in data:
|
|
16
|
+
if param == v.DATAS[0]:
|
|
17
|
+
coverages += [va.AROM_DATAS['wind_u'], va.AROM_DATAS['wind_v']]
|
|
18
|
+
else:
|
|
19
|
+
coverages += [va.AROM_DATAS[param]]
|
|
20
|
+
|
|
26
21
|
# Get latest available forecast date from arome /GetCapabilities api endpoint
|
|
27
22
|
logger.info('Finding latest available forecast')
|
|
28
23
|
session = d.get_session()
|
|
@@ -55,9 +50,10 @@ def download_arom(model, step, data, lat, lon):
|
|
|
55
50
|
|
|
56
51
|
# Select forecast prevision time based on user input
|
|
57
52
|
# 3600 means layer is the prevision for 1h after latestRun
|
|
53
|
+
nbDay = 1 if days == "1" else 2
|
|
58
54
|
times = list(range(
|
|
59
55
|
int(step[:-1]) * 3600,
|
|
60
|
-
|
|
56
|
+
nbDay * 24 * 60 * 60 + 1,
|
|
61
57
|
int(step[:-1]) * 3600)
|
|
62
58
|
)
|
|
63
59
|
logger.debug(f"Forecast to download are {times}")
|
|
@@ -95,14 +91,9 @@ def download_arom(model, step, data, lat, lon):
|
|
|
95
91
|
if i+100 < len(urls):
|
|
96
92
|
logger.info('Sleeping 1 minute...')
|
|
97
93
|
t.sleep(60)
|
|
98
|
-
|
|
99
|
-
#
|
|
100
|
-
|
|
101
|
-
file.unlink(missing_ok=True)
|
|
102
|
-
with open(file, "wb") as outfile:
|
|
103
|
-
for layer in layers:
|
|
104
|
-
if layer:
|
|
105
|
-
outfile.write(layer)
|
|
94
|
+
|
|
95
|
+
# Write the grib file as the concatenation of the layers
|
|
96
|
+
d.write_file(model, latestRun, step, layers)
|
|
106
97
|
|
|
107
98
|
def handle_fetch_error_arom(e):
|
|
108
99
|
if isinstance(e, requests.exceptions.HTTPError):
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from datetime import datetime, timedelta
|
|
2
|
+
|
|
3
|
+
import grib2sail.variables as v
|
|
4
|
+
import grib2sail.variables_gfs as vg
|
|
5
|
+
import grib2sail.downloader as d
|
|
6
|
+
from grib2sail.logger import logger
|
|
7
|
+
|
|
8
|
+
def download_gfs(model, step, days, data, lat, lon):
|
|
9
|
+
session = d.get_session()
|
|
10
|
+
# Get latest available forecast date and run by trying from most recent
|
|
11
|
+
logger.info('Finding latest available forecast')
|
|
12
|
+
date, run = find_latest_forecast(session)
|
|
13
|
+
logger.debug(f"Latest forecast is {date}, {run}z")
|
|
14
|
+
|
|
15
|
+
# Coverages list all the individual layers categories to download
|
|
16
|
+
coverages = []
|
|
17
|
+
for param in data:
|
|
18
|
+
if param == v.DATAS[0]:
|
|
19
|
+
coverages += [vg.GFS_DATAS['wind_u'], vg.GFS_DATAS['wind_v']]
|
|
20
|
+
else:
|
|
21
|
+
coverages += [vg.GFS_DATAS[param]]
|
|
22
|
+
|
|
23
|
+
urls = []
|
|
24
|
+
if int(days) > 16:
|
|
25
|
+
logger.warning(f"Requesting {days} days, max is 16")
|
|
26
|
+
days = "16"
|
|
27
|
+
# Forecast is available on an hourly basis until day 5 then on a 3h basis
|
|
28
|
+
if step == '1h' and days > 5 :
|
|
29
|
+
logger.warning('Only the first 5 days can have a step of 1h, the rest will have a 3h step')
|
|
30
|
+
hours = list(range(0, 120, 1)) + list(range(120, 385, 3))
|
|
31
|
+
else:
|
|
32
|
+
hours = list(range(0, 24 * int(days) + 1, int(step[:-1])))
|
|
33
|
+
for hour in hours:
|
|
34
|
+
url = vg.API_URL
|
|
35
|
+
url += f"?dir=%2Fgfs.{date}%2F{run}%2Fatmos&file=gfs.t{run}z.pgrb2.0p25.f{hour:03d}"
|
|
36
|
+
url += ''.join(coverages) + f"&subregion="
|
|
37
|
+
url += f"&leftlon={lon[0]}&rightlon={lon[1]}" + f"&bottomlat={lat[0]}&toplat={lat[1]}"
|
|
38
|
+
urls.append(url)
|
|
39
|
+
logger.debug(f"First url to download is {urls[0]}")
|
|
40
|
+
layers = d.get_layers(model, urls)
|
|
41
|
+
|
|
42
|
+
# Write the grib file as the concatenation of the layers
|
|
43
|
+
d.write_file(model, f"{date}-{run}z", step, layers)
|
|
44
|
+
|
|
45
|
+
def find_latest_forecast(session):
|
|
46
|
+
today = datetime.today()
|
|
47
|
+
dates = [
|
|
48
|
+
(today + timedelta(days=1)).strftime("%Y%m%d"),
|
|
49
|
+
today.strftime("%Y%m%d"),
|
|
50
|
+
(today - timedelta(days=1)).strftime("%Y%m%d")
|
|
51
|
+
]
|
|
52
|
+
runs = ['18', '12', '06', '00']
|
|
53
|
+
for date in dates:
|
|
54
|
+
for run in runs:
|
|
55
|
+
url = (
|
|
56
|
+
f"{vg.PROD_URL}/gfs.{date}/{run}/atmos/"
|
|
57
|
+
f"gfs.t{run}z.pgrb2.0p25.f000"
|
|
58
|
+
)
|
|
59
|
+
try:
|
|
60
|
+
r = session.head(url, timeout=10)
|
|
61
|
+
if r.status_code == 200:
|
|
62
|
+
return date, run
|
|
63
|
+
else:
|
|
64
|
+
logger.debug(f"Unavailable forecast {url}, status is: {r.status_code}")
|
|
65
|
+
except Exception as e:
|
|
66
|
+
logger.error_exit(f"Download failed: {e}")
|
|
67
|
+
logger.error_exit("Couldn't find the latest available forecat")
|
|
68
|
+
|
grib2sail/variables.py
CHANGED
grib2sail/variables_arom.py
CHANGED
|
@@ -12,6 +12,16 @@ AROM_URLS = {
|
|
|
12
12
|
'token': 'https://portail-api.meteofrance.fr/token',
|
|
13
13
|
f"{v.MODELS[0]}_cov": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-OM-0025-ANTIL-WCS/GetCoverage?service=WCS&version=2.0.1&format=application/wmo-grib',
|
|
14
14
|
f"{v.MODELS[1]}_cov": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-001-FRANCE-WCS/GetCoverage?service=WCS&version=2.0.1&format=application/wmo-grib',
|
|
15
|
+
f"{v.MODELS[2]}_cov": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-0025-FRANCE-WCS/GetCoverage?service=WCS&version=2.0.1&format=application/wmo-grib',
|
|
16
|
+
f"{v.MODELS[3]}_cov": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-OM-0025-GUYANE-WCS/GetCoverage?service=WCS&version=2.0.1&format=application/wmo-grib',
|
|
17
|
+
f"{v.MODELS[4]}_cov": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-OM-0025-INDIEN-WCS/GetCoverage?service=WCS&version=2.0.1&format=application/wmo-grib',
|
|
18
|
+
f"{v.MODELS[5]}_cov": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-OM-0025-NCALED-WCS/GetCoverage?service=WCS&version=2.0.1&format=application/wmo-grib',
|
|
19
|
+
f"{v.MODELS[6]}_cov": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-OM-0025-POLYN-WCS/GetCoverage?service=WCS&version=2.0.1&format=application/wmo-grib',
|
|
15
20
|
f"{v.MODELS[0]}_capa": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-OM-0025-ANTIL-WCS/GetCapabilities?service=WCS&version=1.3.0&language=eng',
|
|
16
21
|
f"{v.MODELS[1]}_capa": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-001-FRANCE-WCS/GetCapabilities?service=WCS&version=1.3.0&language=eng',
|
|
22
|
+
f"{v.MODELS[2]}_capa": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-0025-FRANCE-WCS/GetCapabilities?service=WCS&version=1.3.0&language=eng',
|
|
23
|
+
f"{v.MODELS[3]}_capa": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-OM-0025-GUYANE-WCS/GetCapabilities?service=WCS&version=1.3.0&language=eng',
|
|
24
|
+
f"{v.MODELS[4]}_capa": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-OM-0025-INDIEN-WCS/GetCapabilities?service=WCS&version=1.3.0&language=eng',
|
|
25
|
+
f"{v.MODELS[5]}_capa": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-OM-0025-NCALED-WCS/GetCapabilities?service=WCS&version=1.3.0&language=eng',
|
|
26
|
+
f"{v.MODELS[6]}_capa": 'https://public-api.meteofrance.fr/public/arome/1.0/wcs/MF-NWP-HIGHRES-AROME-OM-0025-POLYN-WCS/GetCapabilities?service=WCS&version=1.3.0&language=eng',
|
|
17
27
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
PROD_URL = 'https://nomads.ncep.noaa.gov/pub/data/nccf/com/gfs/prod'
|
|
2
|
+
API_URL = 'https://nomads.ncep.noaa.gov/cgi-bin/filter_gfs_0p25.pl'
|
|
3
|
+
|
|
4
|
+
GFS_DATAS = {
|
|
5
|
+
'wind_u': '&var_UGRD=on&lev_10_m_above_ground=on',
|
|
6
|
+
'wind_v': '&var_VGRD=on',
|
|
7
|
+
'wind_gust': '&var_GUST=on&lev_surface=on',
|
|
8
|
+
'pressure': '&var_PRMSL=on&lev_mean_sea_level=on',
|
|
9
|
+
'cloud': '&var_TCDC=on&lev_entire_atmosphere=on'
|
|
10
|
+
}
|
|
11
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: grib2sail
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Grib files downloader for sailing purposes
|
|
5
5
|
Author-email: Chinkara <poubelledechinkara@outlook.com>
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -16,15 +16,26 @@ Dynamic: license-file
|
|
|
16
16
|
|
|
17
17
|
# GRIB2Sail
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
Grib files downloader for sailing purposes
|
|
19
|
+
<p align="center">
|
|
20
|
+
<img src="https://raw.githubusercontent.com/Ch1nkara/GRIB2Sail/main/docs/assets/grib2sail_logo.png" alt="GRIB2Sail" width="40%">
|
|
21
|
+
</p>
|
|
22
|
+
<p align="center">
|
|
23
|
+
<em>Grib files downloader for sailing purposes</em>
|
|
24
|
+
</p>
|
|
25
|
+
<p align="center">
|
|
26
|
+
<img src="https://img.shields.io/pypi/v/grib2sail.svg">
|
|
27
|
+
<img src="https://img.shields.io/github/actions/workflow/status/Ch1nkara/GRIB2Sail/release.yml">
|
|
28
|
+
<img src="https://img.shields.io/badge/license-GPL%20v3-blue.svg">
|
|
29
|
+
</p>
|
|
24
30
|
|
|
25
31
|
Currently the supported models are:
|
|
26
|
-
- AROME
|
|
32
|
+
- AROME (001 and 0025)
|
|
27
33
|
- AROME ANTILLE
|
|
34
|
+
- AROME GUYANE
|
|
35
|
+
- AROME INDIEN
|
|
36
|
+
- AROME NOUVELLE CALEDONIE
|
|
37
|
+
- AROME POLYNESIE
|
|
38
|
+
- GFS (0025)
|
|
28
39
|
|
|
29
40
|
## Installation
|
|
30
41
|
|
|
@@ -49,7 +60,7 @@ account on meteofrance.fr. The procedure is as follow:
|
|
|
49
60
|
|
|
50
61
|
## Usage
|
|
51
62
|
|
|
52
|
-
To get the GRIB file
|
|
63
|
+
To get the GRIB file containing the wind, the wind_gust, the atmospheric
|
|
53
64
|
pressure and the cloud coverage for the area between latitude 11.5N - 12.5N
|
|
54
65
|
and longitude 62.5W - 61.5W with a 3 hour step from the AROME ANTILLE model
|
|
55
66
|
run:
|
|
@@ -68,6 +79,6 @@ It can now be imported in a navigation software such as OpenCPN
|
|
|
68
79
|
|
|
69
80
|
This is still the early stage of the development the main upcoming features
|
|
70
81
|
are:
|
|
71
|
-
- adding more supported models (arpege,
|
|
82
|
+
- adding more supported models (arpege, ecmwf...)
|
|
72
83
|
- adding more supported variables (rain, sea state)
|
|
73
84
|
- adding a GUI
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
grib2sail/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
grib2sail/__main__.py,sha256=U5PTpeJRtXGpcO8YPUdCD2hORF8T68IM6JW1-dDyYqE,37
|
|
3
|
+
grib2sail/_version.py,sha256=5zTqm8rgXsWYBpB2M3Zw_K1D-aV8wP7NsBLrmMKkrAQ,704
|
|
4
|
+
grib2sail/cli.py,sha256=CJQyuBoPnKh7wEC_gaPZdlibVK01QO2p3BHYF_Ta6t4,2543
|
|
5
|
+
grib2sail/downloader.py,sha256=Efkgf3Np7bEz6231v-tCjjtnRQC7iULrP8z9tWY2GFA,2175
|
|
6
|
+
grib2sail/downloader_arom.py,sha256=ViGj7-HRW3G_bdBpDvVjEFFOUwJWGwXztVl1AlSLZHk,3789
|
|
7
|
+
grib2sail/downloader_gfs.py,sha256=OVaj3SYw8SozUuBZSxsNVehm8SSHCiND5G0QEfQ6H5c,2439
|
|
8
|
+
grib2sail/logger.py,sha256=_erYrZlKPjhDu-reFkyylodFgSVtOcXJg5F1drYeQNY,456
|
|
9
|
+
grib2sail/token.py,sha256=gNYCBNEGmjMb_RGq79wvtflhKxqiiX4GXpqfMR3eiJ0,1443
|
|
10
|
+
grib2sail/variables.py,sha256=jiirlEbp3T6LicM4KK6Y3iIywdiMMW3qgVPFIHQ1plY,221
|
|
11
|
+
grib2sail/variables_arom.py,sha256=FGYRbDZHXN_ud7dLtT6mempETlkPFaFQDn2zC_3Nfpo,2991
|
|
12
|
+
grib2sail/variables_gfs.py,sha256=D38OwokrJ9rf4r4Wu_sZMhdFOMQqKng4AJ0oEc8hwxE,386
|
|
13
|
+
grib2sail-0.3.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
14
|
+
grib2sail-0.3.0.dist-info/METADATA,sha256=Wiobw0ALc2d_TuntXosNzUnhhbxsQlwTUs-gXumEpME,2866
|
|
15
|
+
grib2sail-0.3.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
16
|
+
grib2sail-0.3.0.dist-info/top_level.txt,sha256=ubF1tLZ8ZWARUC9s6_0fRsuUKbVqOZmrp8UEGEBm8aE,10
|
|
17
|
+
grib2sail-0.3.0.dist-info/RECORD,,
|
grib2sail-0.2.0.dist-info/RECORD
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
grib2sail/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
grib2sail/__main__.py,sha256=U5PTpeJRtXGpcO8YPUdCD2hORF8T68IM6JW1-dDyYqE,37
|
|
3
|
-
grib2sail/_version.py,sha256=Dg8AmJomLVpjKL6prJylOONZAPRtB86LOce7dorQS_A,704
|
|
4
|
-
grib2sail/cli.py,sha256=3IcGISWNF9XpDhSdSqb6z5bnc2YFmKlQKtTPH0M7hzI,2247
|
|
5
|
-
grib2sail/downloader.py,sha256=ZQDaPabDuKlb7CqGxwabI73T5pKC_jVdqcCyT6A6ch4,1566
|
|
6
|
-
grib2sail/downloader_arom.py,sha256=FA9IDvhcBiEY7uJuHTcuLY-Ku4US5uPV5wLks3maNuw,4038
|
|
7
|
-
grib2sail/logger.py,sha256=_erYrZlKPjhDu-reFkyylodFgSVtOcXJg5F1drYeQNY,456
|
|
8
|
-
grib2sail/token.py,sha256=gNYCBNEGmjMb_RGq79wvtflhKxqiiX4GXpqfMR3eiJ0,1443
|
|
9
|
-
grib2sail/variables.py,sha256=M0ZcusbURgPuI1ZbRjnCqRr1Ke-2057cz3EycCHYB2E,133
|
|
10
|
-
grib2sail/variables_arom.py,sha256=RNJZT7O5EFa4HtVYrUuH7EHwxZ9u_63F1vkBUekfOfo,1169
|
|
11
|
-
grib2sail-0.2.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
12
|
-
grib2sail-0.2.0.dist-info/METADATA,sha256=7NqzFLPAM-6KFKU6Dk_bVF74t8FgxfFufzjpFaPJeRE,2545
|
|
13
|
-
grib2sail-0.2.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
14
|
-
grib2sail-0.2.0.dist-info/top_level.txt,sha256=ubF1tLZ8ZWARUC9s6_0fRsuUKbVqOZmrp8UEGEBm8aE,10
|
|
15
|
-
grib2sail-0.2.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|