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: 0 additions & 2 deletions .circleci/install_triggers
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
^\.circleci/
^environment\.yml$
^pyproject.toml$
^setup\.py$
^setup\.cfg$
4 changes: 2 additions & 2 deletions doc/contributing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ previous command. To only run tests from a single file, run the command
pytest tests/unit/test_some_file.py

If you would like to avoid loading the default pytest configuration from
`setup.cfg <https://github.com/ESMValGroup/ESMValCore/blob/main/setup.cfg>`_
`pyproject.toml <https://github.com/ESMValGroup/ESMValCore/blob/main/pyproject.toml>`_
because this can be a bit slow for running just a few tests, use

.. code-block:: bash
Expand Down Expand Up @@ -660,7 +660,7 @@ the following files:
- ``environment.yml``
contains all the development dependencies; these are all from
`conda-forge <https://conda-forge.org/>`_
- ``setup.py``
- ``pyproject.toml``
contains all Python dependencies, regardless of their installation source

Note that packages may have a different name on
Expand Down
2 changes: 1 addition & 1 deletion environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ dependencies:
- dask-jobqueue
- distributed
- esgf-pyclient >=0.3.1
- esmpy !=8.1.0
- esmpy
- filelock
- fiona
- fire
Expand Down
7 changes: 2 additions & 5 deletions esmvalcore/_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,10 @@
import logging
import os
import sys
from importlib.metadata import entry_points
from pathlib import Path
from typing import Optional

if (sys.version_info.major, sys.version_info.minor) < (3, 10):
from importlib_metadata import entry_points
else:
from importlib.metadata import entry_points # type: ignore

import fire

# set up logging
Expand Down Expand Up @@ -583,6 +579,7 @@ def _get_config_info(cli_config_dir):
zip(
config_dirs,
_get_all_config_sources(cli_config_dir),
strict=False,
)
)

Expand Down
2 changes: 1 addition & 1 deletion esmvalcore/_recipe/check.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def _group_years(years):
ends.append(year)

ranges = []
for start, end in zip(starts, ends):
for start, end in zip(starts, ends, strict=False):
ranges.append(f"{start}" if start == end else f"{start}-{end}")

return ", ".join(ranges)
Expand Down
2 changes: 1 addition & 1 deletion esmvalcore/_recipe/from_datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ def _group_ensemble_names(ensemble_names: Iterable[str]) -> list[str]:
groups = []
for ensemble_range in ensemble_ranges:
txt = ""
for name, value in zip("ripf", ensemble_range):
for name, value in zip("ripf", ensemble_range, strict=False):
txt += name
if value[0] == value[1]:
txt += f"{value[0]}"
Expand Down
14 changes: 9 additions & 5 deletions esmvalcore/_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,12 @@ def _get_resource_usage(process, start_time, children=True):
continue

# Create and yield log entry
entries = [sum(entry) for entry in zip(*cache.values())]
entries = [sum(entry) for entry in zip(*cache.values(), strict=False)]
entries.insert(0, time.time() - start_time)
entries = [round(entry, p) for entry, p in zip(entries, precision)]
entries = [
round(entry, p)
for entry, p in zip(entries, precision, strict=False)
]
entries.insert(0, datetime.datetime.utcnow())
max_memory = max(max_memory, entries[4])
yield (fmt.format(*entries), max_memory)
Expand Down Expand Up @@ -609,9 +612,10 @@ def _run(self, input_files):

returncode = None

with resource_usage_logger(process.pid, self.resource_log), open(
self.log, "ab"
) as log:
with (
resource_usage_logger(process.pid, self.resource_log),
open(self.log, "ab") as log,
):
last_line = [""]
while returncode is None:
returncode = process.poll()
Expand Down
4 changes: 2 additions & 2 deletions esmvalcore/preprocessor/_multimodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,13 @@ def _unify_time_coordinates(cubes):
# monthly data
dates = [
datetime(year, month, 15, 0, 0, 0)
for year, month in zip(years, months)
for year, month in zip(years, months, strict=False)
]
elif 0 not in np.diff(days):
# daily data
dates = [
datetime(year, month, day, 0, 0, 0)
for year, month, day in zip(years, months, days)
for year, month, day in zip(years, months, days, strict=False)
]
if coord.units != t_unit:
logger.warning(
Expand Down
5 changes: 4 additions & 1 deletion esmvalcore/preprocessor/_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,10 @@ def spans_full_season(cube: Cube) -> list[bool]:
seasons = cube.coord("clim_season").points
tar_days = [(len(sea) * 29, len(sea) * 31) for sea in seasons]

return [dt[0] <= dn <= dt[1] for dn, dt in zip(num_days, tar_days)]
return [
dt[0] <= dn <= dt[1]
for dn, dt in zip(num_days, tar_days, strict=False)
]

full_seasons = spans_full_season(result)
result = result[full_seasons]
Expand Down
5 changes: 4 additions & 1 deletion esmvalcore/preprocessor/_volume.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,10 @@ def extract_transect(
)

for dim_name, dim_cut, coord in zip(
["latitude", "longitude"], [latitude, longitude], [lats, lons]
["latitude", "longitude"],
[latitude, longitude],
[lats, lons],
strict=False,
):
# ####
# Look for the first coordinate.
Expand Down
210 changes: 189 additions & 21 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,34 +1,174 @@
[build-system]
requires = ["setuptools >= 40.6.0", "wheel", "setuptools_scm>=6.2"]
requires = [
"setuptools >= 40.6.0",
"setuptools_scm>=6.2",
]
build-backend = "setuptools.build_meta"

[project]
authors = [
{name = "ESMValTool Development Team", email = "esmvaltool-dev@listserv.dfn.de"}
]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Environment :: Console",
"Intended Audience :: Developers",
"Intended Audience :: Science/Research",
"License :: OSI Approved :: Apache Software License",
"Natural Language :: English",
"Operating System :: POSIX :: Linux",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Scientific/Engineering",
"Topic :: Scientific/Engineering :: Atmospheric Science",
"Topic :: Scientific/Engineering :: GIS",
"Topic :: Scientific/Engineering :: Hydrology",
"Topic :: Scientific/Engineering :: Physics",
]
dynamic = [
"readme",
"version",
]
dependencies = [
"cartopy",
"cf-units",
"dask[array,distributed]!=2024.8.0", # ESMValCore/issues/2503
"dask-jobqueue",
"esgf-pyclient>=0.3.1",
"esmf-regrid>=0.11.0",
"esmpy", # not on PyPI
"filelock",
"fiona",
"fire",
"geopy",
"humanfriendly",
"iris-grib>=0.20.0", # github.com/ESMValGroup/ESMValCore/issues/2535
"isodate>=0.7.0",
"jinja2",
"nc-time-axis", # needed by iris.plot
"nested-lookup",
"netCDF4",
"numpy!=1.24.3,<2.0.0", # avoid pulling 2.0.0rc1
"packaging",
"pandas",
"pillow",
"prov",
"psutil",
"py-cordex",
"pybtex",
"pyyaml",
"requests",
"scipy>=1.6",
"scitools-iris>=3.10.0",
"shapely>=2.0.0",
"stratify>=0.3",
"yamale",
]
description = "A community tool for pre-processing data from Earth system models in CMIP and running analysis scripts"
license = {text = "Apache License, Version 2.0"}
name = "ESMValCore"
requires-python = ">=3.10"

[project.optional-dependencies]
test = [
"pytest>6.0.0",
"pytest-cov>=2.10.1",
"pytest-env",
"pytest-html!=2.1.0",
"pytest-metadata>=1.5.1",
"pytest-mock",
"pytest-xdist",
"ESMValTool_sample_data==0.0.3",
]
doc = [
"autodocsumm>=0.2.2",
"ipython",
"nbsphinx",
"sphinx>=6.1.3",
"pydata_sphinx_theme",
]
develop = [
"esmvalcore[test,doc]",
"pre-commit",
"pylint",
"pydocstyle",
"vprof",
]

[project.scripts]
esmvaltool = "esmvalcore._main:run"

[project.urls]
Code = "https://github.com/ESMValGroup/ESMValCore"
Community = "https://github.com/ESMValGroup/Community"
Documentation = "https://docs.esmvaltool.org"
Homepage = "https://esmvaltool.org"
Issues = "https://github.com/ESMValGroup/ESMValCore/issues"

[tool.setuptools]
include-package-data = true
license-files = ["LICENSE"]
packages = ["esmvalcore"]
zip-safe = false

[tool.setuptools.dynamic]
readme = {file = "README.md", content-type = "text/markdown"}

[tool.setuptools_scm]
version_scheme = "release-branch-semver"

[tool.codespell]
skip = "*.ipynb,esmvalcore/config/extra_facets/ipslcm-mappings.yml"
ignore-words-list = "vas,hist,oce"
# Configure tests

[tool.pylint.main]
jobs = 1 # Running more than one job in parallel crashes prospector.
ignore-paths = [
"doc/conf.py", # Sphinx configuration file
[tool.pytest.ini_options]
addopts = [
"-ra",
"--strict-config",
"--strict-markers",
"--doctest-modules",
"--ignore=esmvalcore/cmor/tables/",
"--cov-report=xml:test-reports/coverage.xml",
"--cov-report=html:test-reports/coverage_html",
"--html=test-reports/report.html",
]
[tool.pylint.basic]
good-names = [
"_", # Used by convention for unused variables
"i", "j", "k", # Used by convention for indices
"logger", # Our preferred name for the logger
log_cli_level = "INFO"
env = {MPLBACKEND = "Agg"}
log_level = "WARNING"
minversion = "6"
markers = [
"installation: Test requires installation of dependencies",
"use_sample_data: Run functional tests using real data",
]
[tool.pylint.format]
max-line-length = 79
[tool.pylint."messages control"]
disable = [
"import-error", # Needed because Codacy does not install dependencies
"file-ignored", # Disable messages about disabling checks
"line-too-long", # Disable line-too-long as this is taken care of by the formatter.
"locally-disabled", # Disable messages about disabling checks
testpaths = ["tests"]
xfail_strict = true

[tool.coverage.run]
parallel = true
source = ["esmvalcore"]

[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"if __name__ == .__main__.:",
"if TYPE_CHECKING:",
]

# Configure type checks

[tool.mypy]
# See https://mypy.readthedocs.io/en/stable/config_file.html
ignore_missing_imports = true
enable_error_code = [
"truthy-bool",
]

# Configure linters

[tool.codespell]
skip = "*.ipynb,esmvalcore/config/extra_facets/ipslcm-mappings.yml"
ignore-words-list = "vas,hist,oce"

[tool.ruff]
line-length = 79
[tool.ruff.lint]
Expand Down Expand Up @@ -59,3 +199,31 @@ ignore = [
known-first-party = ["esmvalcore"]
[tool.ruff.lint.pydocstyle]
convention = "numpy"

# Configure linters that are run by Prospector
# TODO: remove once we have enabled all ruff rules for the tools provided by
# Prospector, see https://github.com/ESMValGroup/ESMValCore/issues/2528.

[tool.pylint.main]
jobs = 1 # Running more than one job in parallel crashes prospector.
ignore-paths = [
"doc/conf.py", # Sphinx configuration file
]
[tool.pylint.basic]
good-names = [
"_", # Used by convention for unused variables
"i", "j", "k", # Used by convention for indices
"logger", # Our preferred name for the logger
]
[tool.pylint.format]
max-line-length = 79
[tool.pylint."messages control"]
disable = [
"import-error", # Needed because Codacy does not install dependencies
"file-ignored", # Disable messages about disabling checks
"line-too-long", # Disable line-too-long as this is taken care of by the formatter.
"locally-disabled", # Disable messages about disabling checks
]

[tool.pydocstyle]
convention = "numpy"
Loading