Skip to content

Commit

Permalink
Enable ruff flake8-bugbear rule (#2536)
Browse files Browse the repository at this point in the history
Co-authored-by: Manuel Schlund <[email protected]>
  • Loading branch information
bouweandela and schlunma authored Oct 16, 2024
1 parent a3557ec commit 1227b2f
Show file tree
Hide file tree
Showing 30 changed files with 164 additions and 76 deletions.
2 changes: 1 addition & 1 deletion doc/contributing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,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 @@ -2451,7 +2451,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

0 comments on commit 1227b2f

Please sign in to comment.