Skip to content
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
2 changes: 1 addition & 1 deletion doc/contributing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ that feature should be removed in version 2.7:
"ESMValCore version 2.5 and is scheduled for removal in "
"version 2.7. Add additional text (e.g., description of "
"alternatives) here.")
warnings.warn(deprecation_msg, ESMValCoreDeprecationWarning)
warnings.warn(deprecation_msg, ESMValCoreDeprecationWarning, stacklevel=2)

# Other code

Expand Down
4 changes: 2 additions & 2 deletions doc/recipe/preprocessor.rst
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ See also :func:`esmvalcore.preprocessor.weighting_landsea_fraction`.
.. _masking:

Masking
=======
========

Introduction to masking
-----------------------
Expand Down Expand Up @@ -2423,7 +2423,7 @@ See also :func:`esmvalcore.preprocessor.linear_trend_stderr`.
.. _detrend:

Detrend
=======
========

ESMValCore also supports detrending along any dimension using
the preprocessor function 'detrend'.
Expand Down
20 changes: 10 additions & 10 deletions esmvalcore/_recipe/check.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ def ncl_version():
try:
cmd = [ncl, "-V"]
version = subprocess.check_output(cmd, universal_newlines=True)
except subprocess.CalledProcessError:
logger.error("Failed to execute '%s'", " ".join(" ".join(cmd)))
except subprocess.CalledProcessError as exc:
logger.error("Failed to execute '%s'", " ".join(cmd))
raise RecipeError(
"Recipe contains NCL scripts, but your NCL "
"installation appears to be broken."
)
) from exc

version = version.strip()
logger.info("Found NCL version %s", version)
Expand Down Expand Up @@ -383,7 +383,7 @@ def _check_duration_periods(timerange):
f"{timerange[0]} is not valid duration according to ISO 8601."
+ "\n"
+ str(exc)
)
) from exc
elif timerange[1].startswith("P"):
try:
isodate.parse_duration(timerange[1])
Expand All @@ -393,7 +393,7 @@ def _check_duration_periods(timerange):
f"{timerange[1]} is not valid duration according to ISO 8601."
+ "\n"
+ str(exc)
)
) from exc


def _check_format_years(date):
Expand Down Expand Up @@ -423,7 +423,7 @@ def _check_timerange_values(date, timerange):
"for dates and duration periods, or be "
"set to '*' to load available years. "
f"Got {timerange} instead." + "\n" + str(exc)
)
) from exc


def valid_time_selection(timerange):
Expand Down Expand Up @@ -584,7 +584,7 @@ def _check_regular_stat(step, step_settings):
try:
get_iris_aggregator(operator, **operator_kwargs)
except ValueError as exc:
raise RecipeError(f"Invalid options for {step}: {exc}")
raise RecipeError(f"Invalid options for {step}: {exc}") from exc


def _check_mm_stat(step, step_settings):
Expand All @@ -594,11 +594,11 @@ def _check_mm_stat(step, step_settings):
try:
(operator, kwargs) = _get_operator_and_kwargs(stat)
except ValueError as exc:
raise RecipeError(str(exc))
raise RecipeError(str(exc)) from exc
try:
get_iris_aggregator(operator, **kwargs)
except ValueError as exc:
raise RecipeError(f"Invalid options for {step}: {exc}")
raise RecipeError(f"Invalid options for {step}: {exc}") from exc


def regridding_schemes(settings: dict):
Expand Down Expand Up @@ -645,4 +645,4 @@ def regridding_schemes(settings: dict):
f"https://docs.esmvaltool.org/projects/ESMValCore/en/latest"
f"/recipe/preprocessor.html#generic-regridding-schemes for "
f"details."
)
) from exc
12 changes: 7 additions & 5 deletions esmvalcore/_recipe/recipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,11 +418,11 @@ def _update_multiproduct(input_products, order, preproc_dir, step):
called from the input products, the products that are created here need to
be added to their ancestors products' settings ().
"""
products = {p for p in input_products if step in p.settings}
if not products:
multiproducts = {p for p in input_products if step in p.settings}
if not multiproducts:
return input_products, {}

settings = list(products)[0].settings[step]
settings = list(multiproducts)[0].settings[step]

if step == "ensemble_statistics":
check.ensemble_statistics_preproc(settings)
Expand All @@ -431,14 +431,16 @@ def _update_multiproduct(input_products, order, preproc_dir, step):
check.multimodel_statistics_preproc(settings)
grouping = settings.get("groupby", None)

downstream_settings = _get_downstream_settings(step, order, products)
downstream_settings = _get_downstream_settings(step, order, multiproducts)

relevant_settings = {
"output_products": defaultdict(dict)
} # pass to ancestors

output_products = set()
for identifier, products in _group_products(products, by_key=grouping):
for identifier, products in _group_products(
multiproducts, by_key=grouping
):
common_attributes = _get_common_attributes(products, settings)

statistics = settings.get("statistics", [])
Expand Down
4 changes: 2 additions & 2 deletions esmvalcore/cmor/_fixes/fix.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def get_cube_from_list(

Raises
------
Exception
ValueError
No cube is found.

Returns
Expand All @@ -155,7 +155,7 @@ def get_cube_from_list(
for cube in cubes:
if cube.var_name == short_name:
return cube
raise Exception(f'Cube for variable "{short_name}" not found')
raise ValueError(f'Cube for variable "{short_name}" not found')

def fix_data(self, cube: Cube) -> Cube:
"""Apply fixes to the data of the cube.
Expand Down
12 changes: 7 additions & 5 deletions esmvalcore/config/_config_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def __init__(self, *args, **kwargs):
"Do not instantiate `Config` objects directly, this will lead "
"to unexpected behavior. Use `esmvalcore.config.CFG` instead."
)
warnings.warn(msg, UserWarning)
warnings.warn(msg, UserWarning, stacklevel=2)

# TODO: remove in v2.14.0
@classmethod
Expand Down Expand Up @@ -313,7 +313,7 @@ def load_from_file(
"ESMValCore version 2.12.0 and is scheduled for removal in "
"version 2.14.0. Please use `CFG.load_from_dirs()` instead."
)
warnings.warn(msg, ESMValCoreDeprecationWarning)
warnings.warn(msg, ESMValCoreDeprecationWarning, stacklevel=2)
self.clear()
self.update(Config._load_user_config(filename))

Expand Down Expand Up @@ -399,7 +399,9 @@ def reload(self) -> None:
f"alternatively use a custom `--config_dir`) and omit "
f"`--config_file`."
)
warnings.warn(deprecation_msg, ESMValCoreDeprecationWarning)
warnings.warn(
deprecation_msg, ESMValCoreDeprecationWarning, stacklevel=2
)
self.update(Config._load_user_config(raise_exception=False))
return

Expand Down Expand Up @@ -505,7 +507,7 @@ def __init__(self, config: dict, name: str = "session"):
"to unexpected behavior. Use "
"`esmvalcore.config.CFG.start_session` instead."
)
warnings.warn(msg, UserWarning)
warnings.warn(msg, UserWarning, stacklevel=2)

def set_session_name(self, name: str = "session"):
"""Set the name for the session.
Expand Down Expand Up @@ -556,7 +558,7 @@ def config_dir(self):
"ESMValCore version 2.12.0 and is scheduled for removal in "
"version 2.14.0."
)
warnings.warn(msg, ESMValCoreDeprecationWarning)
warnings.warn(msg, ESMValCoreDeprecationWarning, stacklevel=2)
if self.get("config_file") is None:
return None
return Path(self["config_file"]).parent
Expand Down
4 changes: 2 additions & 2 deletions esmvalcore/config/_config_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ def validate_extra_facets_dir(value):
"ESMValCore version 2.12.0 and is scheduled for removal in "
"version 2.14.0. Please use a list instead."
)
warnings.warn(msg, ESMValCoreDeprecationWarning)
warnings.warn(msg, ESMValCoreDeprecationWarning, stacklevel=2)
value = list(value)
return validate_pathlist(value)

Expand Down Expand Up @@ -371,7 +371,7 @@ def _handle_deprecation(
f"been deprecated in ESMValCore version {deprecated_version} and is "
f"scheduled for removal in version {remove_version}.{more_info}"
)
warnings.warn(deprecation_msg, ESMValCoreDeprecationWarning)
warnings.warn(deprecation_msg, ESMValCoreDeprecationWarning, stacklevel=2)


# TODO: remove in v2.14.0
Expand Down
1 change: 1 addition & 0 deletions esmvalcore/config/_validated_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ def check_missing(self):
warnings.warn(
f"`{key}` is not defined{more_info}",
MissingConfigParameter,
stacklevel=1,
)

def copy(self):
Expand Down
1 change: 1 addition & 0 deletions esmvalcore/experimental/_warnings.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ def _warning_formatter(message, category, filename, lineno, line=None):
"\n Thank you for trying out the new ESMValCore API."
"\n Note that this API is experimental and may be subject to change."
"\n More info: https://github.com/ESMValGroup/ESMValCore/issues/498",
stacklevel=1,
)
4 changes: 2 additions & 2 deletions esmvalcore/preprocessor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -717,13 +717,13 @@ def _run(self, _):
if step in product.settings:
product.apply(step, self.debug)
if block == blocks[-1]:
product.cubes # pylint: disable=pointless-statement
product.cubes # noqa: B018 pylint: disable=pointless-statement
product.close()
saved.add(product.filename)

for product in self.products:
if product.filename not in saved:
product.cubes # pylint: disable=pointless-statement
product.cubes # noqa: B018 pylint: disable=pointless-statement
product.close()

metadata_files = write_metadata(
Expand Down
2 changes: 1 addition & 1 deletion esmvalcore/preprocessor/_derive/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def _get_all_derived_variables():
module = importlib.import_module(
f"esmvalcore.preprocessor._derive.{short_name}"
)
derivers[short_name] = getattr(module, "DerivedVariable")
derivers[short_name] = module.DerivedVariable
return derivers


Expand Down
4 changes: 2 additions & 2 deletions esmvalcore/preprocessor/_derive/ctotal.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ def calculate(cubes):
c_soil_cube = cubes.extract_cube(
Constraint(name="soil_mass_content_of_carbon")
)
except iris.exceptions.ConstraintMismatchError:
except iris.exceptions.ConstraintMismatchError as exc:
raise ValueError(
f"No cube from {cubes} can be loaded with "
f"standard name CMIP5: soil_carbon_content "
f"or CMIP6: soil_mass_content_of_carbon"
)
) from exc
c_veg_cube = cubes.extract_cube(
Constraint(name="vegetation_carbon_content")
)
Expand Down
2 changes: 1 addition & 1 deletion esmvalcore/preprocessor/_derive/ohc.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def calculate(cubes):
contains_dimension=t_coord_dim, dim_coords=False
)
]
for coord, dims in dim_coords + aux_coords:
for coord, _ in dim_coords + aux_coords:
cube.remove_coord(coord)
new_cube = cube * volume
new_cube *= RHO_CP
Expand Down
2 changes: 1 addition & 1 deletion esmvalcore/preprocessor/_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ def _sort_cubes_by_time(cubes):
msg = "One or more cubes {} are missing".format(
cubes
) + " time coordinate: {}".format(str(exc))
raise ValueError(msg)
raise ValueError(msg) from exc
except TypeError as error:
msg = (
"Cubes cannot be sorted "
Expand Down
4 changes: 2 additions & 2 deletions esmvalcore/preprocessor/_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,10 @@ def ref_to_dims_index_as_index(cube, ref):
"""Get dim for index ref."""
try:
dim = int(ref)
except (ValueError, TypeError):
except (ValueError, TypeError) as exc:
raise ValueError(
"{} Incompatible type {} for slicing".format(ref, type(ref))
)
) from exc
if dim < 0 or dim > cube.ndim:
msg = (
"Requested an iterator over a dimension ({}) "
Expand Down
4 changes: 2 additions & 2 deletions esmvalcore/preprocessor/_regrid.py
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,7 @@ def _load_scheme(src_cube: Cube, tgt_cube: Cube, scheme: str | dict):
"version 2.11.0, ESMValCore is able to determine the most "
"suitable regridding scheme based on the input data."
)
warnings.warn(msg, ESMValCoreDeprecationWarning)
warnings.warn(msg, ESMValCoreDeprecationWarning, stacklevel=2)
scheme = "nearest"

if scheme == "linear_extrapolate":
Expand All @@ -601,7 +601,7 @@ def _load_scheme(src_cube: Cube, tgt_cube: Cube, scheme: str | dict):
"latest/recipe/preprocessor.html#generic-regridding-schemes)."
"This is an exact replacement."
)
warnings.warn(msg, ESMValCoreDeprecationWarning)
warnings.warn(msg, ESMValCoreDeprecationWarning, stacklevel=2)
scheme = "linear"
loaded_scheme = Linear(extrapolation_mode="extrapolate")
logger.debug("Loaded regridding scheme %s", loaded_scheme)
Expand Down
10 changes: 5 additions & 5 deletions esmvalcore/preprocessor/_regrid_esmpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
try:
import ESMF as esmpy # noqa: N811
except ImportError:
raise exc
raise exc from None
import warnings

import iris
Expand Down Expand Up @@ -78,8 +78,8 @@ def __init__(
):
"""Initialize class instance."""
# These regridders are not lazy, so load source and target data once.
src_cube.data # pylint: disable=pointless-statement
tgt_cube.data # pylint: disable=pointless-statement
src_cube.data # # noqa: B018 pylint: disable=pointless-statement
tgt_cube.data # # noqa: B018 pylint: disable=pointless-statement
self.src_cube = src_cube
self.tgt_cube = tgt_cube
self.method = method
Expand All @@ -100,7 +100,7 @@ def __call__(self, cube: Cube) -> Cube:

"""
# These regridders are not lazy, so load source data once.
cube.data # pylint: disable=pointless-statement
cube.data # # noqa: B018 pylint: disable=pointless-statement
src_rep, dst_rep = get_grid_representants(cube, self.tgt_cube)
regridder = build_regridder(
src_rep, dst_rep, self.method, mask_threshold=self.mask_threshold
Expand Down Expand Up @@ -140,7 +140,7 @@ def __init__(self, mask_threshold: float = 0.99):
"`esmvalcore.preprocessor.regrid_schemes.IrisESMFRegrid` "
"instead."
)
warnings.warn(msg, ESMValCoreDeprecationWarning)
warnings.warn(msg, ESMValCoreDeprecationWarning, stacklevel=2)
self.mask_threshold = mask_threshold

def __repr__(self) -> str:
Expand Down
2 changes: 1 addition & 1 deletion esmvalcore/preprocessor/_shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def get_iris_aggregator(
except (ValueError, TypeError) as exc:
raise ValueError(
f"Invalid kwargs for operator '{operator}': {str(exc)}"
)
) from exc

return (aggregator, aggregator_kwargs)

Expand Down
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ disable = [
line-length = 79
[tool.ruff.lint]
select = [
"B",
"E", # pycodestyle
"F", # pyflakes
"I", # isort
Expand All @@ -42,5 +43,9 @@ select = [
ignore = [
"E501", # Disable line-too-long as this is taken care of by the formatter.
]
[tool.ruff.lint.per-file-ignores]
"tests/**.py" = [
"B011", # `assert False` is valid test code.
]
[tool.ruff.lint.isort]
known-first-party = ["esmvalcore"]
Loading