Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prepare for v0.1.17 Bat Release 🦇 #394

Merged
merged 12 commits into from
Sep 20, 2024
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
1 change: 0 additions & 1 deletion argopy/data_fetchers/erddap_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -620,7 +620,6 @@ def getNfromncHeader(url):
N += getNfromncHeader(url)
return N


def post_process(
self, this_ds, add_dm: bool = True, URI: list = None
): # noqa: C901
Expand Down
1 change: 0 additions & 1 deletion argopy/data_fetchers/erddap_refdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ def _add_attributes(self, this): # noqa: C901

return this


@property
def _minimal_vlist(self):
"""Return the minimal list of variables to retrieve measurements for"""
Expand Down
1 change: 0 additions & 1 deletion argopy/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,4 +194,3 @@ def __init__(self, reason: str = None, version: str = None, ignore_caller: List

else:
raise TypeError(repr(type(reason)))

51 changes: 28 additions & 23 deletions argopy/fetchers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@
import logging

from .options import OPTIONS, _VALIDATORS
from .errors import InvalidFetcherAccessPoint, InvalidFetcher, OptionValueError, OptionDeprecatedWarning
from .errors import (
InvalidFetcherAccessPoint,
InvalidFetcher,
OptionValueError,
OptionDeprecatedWarning,
)
from .related import (
get_coriolis_profile_id,
)
from .utils.checkers import (
is_box,
is_indexbox,
check_wmo,
check_cyc
)
from .utils.checkers import is_box, is_indexbox, check_wmo, check_cyc
from .utils.lists import (
list_available_data_src,
list_available_index_src,
Expand Down Expand Up @@ -166,12 +166,15 @@ def __init__(self, mode: str = "", src: str = "", ds: str = "", **fetcher_kwargs
if self._src == "argovis" and (
self._mode == "expert" or self._mode == "research"
):
raise OptionValueError("The 'argovis' data source fetching is only available in 'standard' user mode")
raise OptionValueError(
"The 'argovis' data source fetching is only available in 'standard' user mode"
)

if self._src == "gdac" and "ftp" in self.fetcher_kwargs:
OptionDeprecatedWarning(reason="The GDAC 'ftp' argument is deprecated, it will be replaced by 'gdac' in versions >= 0.1.18",
version="v0.0.17")

OptionDeprecatedWarning(
reason="The GDAC 'ftp' argument is deprecated, it will be replaced by 'gdac' in versions >= 0.1.18",
version="v0.0.17",
)

def __repr__(self):
para = (
Expand Down Expand Up @@ -306,7 +309,7 @@ def domain(self):

@property
def mission(self):
if self._dataset_id == 'bgc':
if self._dataset_id == "bgc":
return "BGC"
else:
return "core+deep"
Expand Down Expand Up @@ -530,18 +533,21 @@ def to_index(self, full: bool = False, coriolis_id: bool = False):
:class:`pandas.DataFrame`
Argo-like index of fetched data
"""

def prt(txt):
msg = [txt]
if self._request != self.__repr__():
msg.append(self._request)
log.debug("\n".join(msg))

def add_coriolis(this_df):
if 'id' not in this_df:
if "id" not in this_df:
this_df["id"] = None

def fc(row):
row["id"] = get_coriolis_profile_id(row["wmo"], row["cyc"])["ID"].values[0]
row["id"] = get_coriolis_profile_id(row["wmo"], row["cyc"])[
"ID"
].values[0]
return row

this_df = this_df.apply(fc, axis=1)
Expand All @@ -550,7 +556,9 @@ def fc(row):
# With the gdac and erddap+bgc,
# we rely on the fetcher ArgoIndex:
# (hence we always return a full index)
if (self._src == 'erddap' and self._dataset_id == 'bgc') or (self._src == 'gdac'):
if (self._src == "erddap" and self._dataset_id == "bgc") or (
self._src == "gdac"
):
prt("to_index working with fetcher ArgoIndex instance")
idx = self.fetcher.indexfs
if self._AccessPoint == "region":
Expand All @@ -564,7 +572,9 @@ def fc(row):
if self._AccessPoint == "float":
idx.search_wmo(self._AccessPoint_data["wmo"])
if self._AccessPoint == "profile":
idx.search_wmo_cyc(self._AccessPoint_data["wmo"], self._AccessPoint_data["cyc"])
idx.search_wmo_cyc(
self._AccessPoint_data["wmo"], self._AccessPoint_data["cyc"]
)

# Then export search result to Index dataframe:
df = idx.to_dataframe()
Expand Down Expand Up @@ -611,14 +621,14 @@ def fc(row):
df = add_coriolis(df) if coriolis_id else df

# Possibly replace the light index with the full version:
if 'profiler_code' not in df or self._request == self.__repr__():
if "profiler_code" not in df or self._request == self.__repr__():
prt("to_index replaced the light index with the full version")
self._index = df

return df

def load(self, force: bool = False, **kwargs):
""" Fetch data (and compute a profile index) if not already in memory
"""Fetch data (and compute a profile index) if not already in memory

Apply the default to_xarray() and to_index() methods and store results in memory.
You can access loaded measurements structure with the `data` and `index` properties.
Expand Down Expand Up @@ -752,11 +762,6 @@ def __init__(
_VALIDATORS["src"](self._src)

# Load data source access points:
if self._src == "localftp":
raise ValueError(
"The 'localftp' data source is deprecated. It's been replaced by 'gdac'."
)

if self._src not in AVAILABLE_INDEX_SOURCES:
raise InvalidFetcher(
"Requested index fetcher '%s' not available ! "
Expand Down
127 changes: 71 additions & 56 deletions argopy/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,28 @@
# Like always, largely inspired by xarray code:
# https://github.com/pydata/xarray/blob/cafab46aac8f7a073a32ec5aa47e213a9810ed54/xarray/core/options.py
"""

import os
import warnings
import logging
import fsspec
from fsspec.core import split_protocol
from socket import gaierror
from urllib.parse import urlparse
from .errors import OptionValueError, FtpPathError, ErddapPathError, OptionDeprecatedWarning
from .errors import (
OptionValueError,
FtpPathError,
ErddapPathError,
OptionDeprecatedWarning,
)

# Define a logger
log = logging.getLogger("argopy.options")

# Define option names as seen by users:
DATA_SOURCE = "src"
FTP = "ftp"
ERDDAP = 'erddap'
ERDDAP = "erddap"
DATASET = "dataset"
CACHE_FOLDER = "cachedir"
CACHE_EXPIRATION = "cache_expiration"
Expand Down Expand Up @@ -62,15 +68,15 @@ def _positive_integer(value):

def validate_ftp(this_path):
if this_path != "-":
return check_gdac_path(this_path, errors='raise')
return check_gdac_path(this_path, errors="raise")
else:
log.debug("OPTIONS['%s'] is not defined" % FTP)
return False


def validate_http(this_path):
if this_path != "-":
return check_erddap_path(this_path, errors='raise')
return check_erddap_path(this_path, errors="raise")
else:
log.debug("OPTIONS['%s'] is not defined" % ERDDAP)
return False
Expand Down Expand Up @@ -186,16 +192,20 @@ def __init__(self, **kwargs):
raise OptionValueError(f"option {k!r} given an invalid value: {v!r}")
self.old[k] = OPTIONS[k]

if k == 'dataset':
OptionDeprecatedWarning(reason="The 'dataset' option is deprecated, it will be replaced by 'ds' in "
"versions >= 0.1.18",
version="v0.0.17",
ignore_caller='test_opt_dataset')
if k == "dataset":
OptionDeprecatedWarning(
reason="The 'dataset' option is deprecated, it will be replaced by 'ds' in "
"versions >= 0.1.18",
version="v0.0.17",
ignore_caller="test_opt_dataset",
)

if k == 'ftp':
OptionDeprecatedWarning(reason="The 'ftp' option is deprecated, it will be replaced by 'gdac' in "
"versions >= 0.1.18",
version="v0.0.17")
if k == "ftp":
OptionDeprecatedWarning(
reason="The 'ftp' option is deprecated, it will be replaced by 'gdac' in "
"versions >= 0.1.18",
version="v0.0.17",
)

self._apply_update(kwargs)

Expand All @@ -214,9 +224,9 @@ def reset_options():
set_options(**DEFAULT)


def check_erddap_path(path, errors='ignore'):
def check_erddap_path(path, errors="ignore"):
"""Check if an url points to an ERDDAP server"""
fs = fsspec.filesystem('http', ssl=False)
fs = fsspec.filesystem("http", ssl=False)
check1 = fs.exists(path + "/info/index.json")
if check1:
return True
Expand All @@ -230,60 +240,62 @@ def check_erddap_path(path, errors='ignore'):
return False


def check_gdac_path(path, errors='ignore'): # noqa: C901
""" Check if a path has the expected GDAC ftp structure

Check if a path is structured like:
.
└── dac
├── aoml
├── ...
├── coriolis
├── ...
├── meds
└── nmdis

Examples:
>>> check_gdac_path("https://data-argo.ifremer.fr") # True
>>> check_gdac_path("ftp://ftp.ifremer.fr/ifremer/argo") # True
>>> check_gdac_path("ftp://usgodae.org/pub/outgoing/argo") # True
>>> check_gdac_path("/home/ref-argo/gdac") # True
>>> check_gdac_path("https://www.ifremer.fr") # False
>>> check_gdac_path("ftp://usgodae.org/pub/outgoing") # False

Parameters
----------
path: str
Path name to check, including access protocol
errors: str
"ignore" or "raise" (or "warn")

Returns
-------
checked: boolean
True if at least one DAC folder is found under path/dac/<dac_name>
False otherwise
def check_gdac_path(path, errors="ignore"): # noqa: C901
"""Check if a path has the expected GDAC ftp structure

Check if a path is structured like:
.
└── dac
├── aoml
├── ...
├── coriolis
├── ...
├── meds
└── nmdis

Examples:
>>> check_gdac_path("https://data-argo.ifremer.fr") # True
>>> check_gdac_path("ftp://ftp.ifremer.fr/ifremer/argo") # True
>>> check_gdac_path("ftp://usgodae.org/pub/outgoing/argo") # True
>>> check_gdac_path("/home/ref-argo/gdac") # True
>>> check_gdac_path("https://www.ifremer.fr") # False
>>> check_gdac_path("ftp://usgodae.org/pub/outgoing") # False

Parameters
----------
path: str
Path name to check, including access protocol
errors: str
"ignore" or "raise" (or "warn")

Returns
-------
checked: boolean
True if at least one DAC folder is found under path/dac/<dac_name>
False otherwise
"""
# Create a file system for this path
if split_protocol(path)[0] is None:
fs = fsspec.filesystem('file')
elif split_protocol(path)[0] in ['https', 'http']:
fs = fsspec.filesystem('http')
elif 'ftp' in split_protocol(path)[0]:
fs = fsspec.filesystem("file")
elif split_protocol(path)[0] in ["https", "http"]:
fs = fsspec.filesystem("http")
elif "ftp" in split_protocol(path)[0]:
try:
host = urlparse(path).hostname
port = 0 if urlparse(path).port is None else urlparse(path).port
fs = fsspec.filesystem('ftp', host=host, port=port)
fs = fsspec.filesystem("ftp", host=host, port=port)
except gaierror:
if errors == 'raise':
if errors == "raise":
raise FtpPathError("Can't get address info (GAIerror) on '%s'" % host)
elif errors == "warn":
warnings.warn("Can't get address info (GAIerror) on '%s'" % host)
return False
else:
return False
else:
raise FtpPathError("Unknown protocol for an Argo GDAC host: %s" % split_protocol(path)[0])
raise FtpPathError(
"Unknown protocol for an Argo GDAC host: %s" % split_protocol(path)[0]
)

# dacs = [
# "aoml",
Expand All @@ -310,7 +322,10 @@ def check_gdac_path(path, errors='ignore'): # noqa: C901
return True

elif errors == "raise":
raise FtpPathError("This path is not GDAC compliant (no `dac` folder with legitimate sub-folder):\n%s" % path)
raise FtpPathError(
"This path is not GDAC compliant (no `dac` folder with legitimate sub-folder):\n%s"
% path
)

elif errors == "warn":
warnings.warn("This path is not GDAC compliant:\n%s" % path)
Expand Down
2 changes: 1 addition & 1 deletion argopy/related/argo_documentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def parse(self, file):
else:
# print("-", line)
record[tag].append(line)
except UnboundLocalError as e:
except UnboundLocalError:
pass
elif len(line) == 2:
record[line] = []
Expand Down
12 changes: 5 additions & 7 deletions argopy/related/reference_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@ class ArgoNVSReferenceTables:

valid_ref = [
"R01",
"RR2",
"RD2",
"RP2",
"R03",
"R04",
"R05",
Expand All @@ -46,8 +43,6 @@ class ArgoNVSReferenceTables:
"R12",
"R13",
"R15",
"RMC",
"RTV",
"R16",
"R18",
"R19",
Expand All @@ -60,9 +55,12 @@ class ArgoNVSReferenceTables:
"R26",
"R27",
"R28",
"R29",
"R30",
"R40",
"RD2",
"RMC",
"RP2",
"RR2",
"RTV",
]
"""List of all available Reference Tables"""

Expand Down
Loading
Loading