[build-system]
requires = [
    "setuptools>=80",
    "setuptools_scm>=8",
]
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",
    "Natural Language :: English",
    "Operating System :: POSIX :: Linux",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.12",
    "Programming Language :: Python :: 3.13",
    "Topic :: Scientific/Engineering",
    "Topic :: Scientific/Engineering :: Atmospheric Science",
    "Topic :: Scientific/Engineering :: GIS",
    "Topic :: Scientific/Engineering :: Hydrology",
    "Topic :: Scientific/Engineering :: Physics",
]
dynamic = [
    "readme",
    "version",
]
dependencies = [
    "aiohttp",
    "cartopy",
    "cf-units",
    "dask[array,distributed]>=2025",  # Core/issues/2503
    "dask-jobqueue",
    "esgf-pyclient>=0.3.1",
    "esmf-regrid>=0.11.0",
    "filelock",
    "fiona",
    "fire",
    "geopy",
    "humanfriendly",
    "intake-esgf>=2026.4.28",
    "intake-esm",
    "iris-grib>=0.20.0",  # github.com/ESMValGroup/ESMValCore/issues/2535
    "isodate>=0.7.0",
    "jinja2",
    "nc-time-axis",  # needed by iris.plot
    "ncdata",
    "nested-lookup",
    "netCDF4",
    "numpy!=1.24.3",
    "packaging",
    "pandas",
    "pillow",
    "prov",
    "psutil",
    "py-cordex",
    "pybtex",
    "pyyaml",
    "requests",
    "rich",
    "scipy>=1.6",
    "scitools-iris",
    "shapely>=2.0.0",
    "stratify>=0.3",
    "xarray",
    "yamale",
    "zarr>3",
]
description = "A community tool for pre-processing data from Earth system models in CMIP and running analysis scripts"
license = "Apache-2.0"
license-files = ["LICENSE", "NOTICE"]
name = "ESMValCore"
requires-python = ">=3.12"

[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]
packages = ["esmvalcore"]

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

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

# Configure tests

[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",
]
env = {MPLBACKEND = "Agg"}
filterwarnings = [
    "ignore:Do not instantiate `Config` objects directly:UserWarning"
]
log_cli_level = "INFO"
log_level = "WARNING"
minversion = "6"
markers = [
    "use_sample_data: Run functional tests using real data",
    "online: Run tests that require internet access",
]
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
packages = "esmvalcore"
ignore_missing_imports = true
enable_error_code = [
    "truthy-bool",
]
exclude = [
  "^doc/conf.py$",
  "esmvalcore/cmor/tables/",
]

# Configure linters

[tool.codespell]
skip = "*.ipynb,esmvalcore/config/extra_facets/ipslcm-mappings.yml,tests/sample_data/iris-sample-data/LICENSE"
ignore-words-list = "emac,hist,oce,pres,vas"

[tool.ruff]
line-length = 79
[tool.ruff.lint]
select = ["ALL"]
ignore = [
    # Ignore until someone has time to fix this:
    "DTZ",      # add tzinfo to datetimes
    "FBT",      # avoid boolean positional arguments
    "N818",     # Exception name should be named with an Error suffix
    "PERF",     # Use comprehensions
    "PGH003",   # Use specific rule codes when ignoring type issues
    "PLR2004",  # Don't use magic values
    "PT009",    # Use a regular `assert` instead of unittest-style `assertListEqual`
    "PT011",    # pytest.raises without match argument
    "PT027",    # Use `pytest.raises` instead of unittest-style `assertRaises`
    "PTH",      # Use pathlib everywhere
    "SIM102",   # Use a single `if` statement instead of nested `if` statements
    "SIM117",   # Use a single `with` statement with multiple contexts instead of nested `with` statements
    "TD003",    # Missing issue link on the line following this TODO
    "TRY400",   # Uses of `logging.error` instead of `logging.exception` when logging an exception
    # Really ignore:
    "D105",     # Disable missing docstring in magic method as these are well defined.
    "E501",     # Disable line-too-long as this is taken care of by the formatter.
    "FIX002",   # TODOs can be useful when something cannot be done immediately.
    "PLW1641",  # Implementing __hash__ on mutable objects may be more confusing than not doing it.
    "S603",     # Uncheckable
    "TD002",    # Missing author in TODO: can be seen from git history
    "TRY003",   # Fixing this would require many exceptions
]
future-annotations = true
[tool.ruff.lint.per-file-ignores]
"**.ipynb" = [
    "T20",      # Printing things in notebooks is fine.
]
"tests/**.py" = [
    "ARG",      # Fixtures that set up some state are wrongly identified as unused arguments.
    "S101",     # Use of assert in tests code is required.
    "T20",      # Printing things can help with debugging tests.
    "SLF001",   # Testing private members is ok
    "PLR2004",  # Magic values in tests are fine.
    # Docstrings in tests are only needed if the code is not self-explanatory.
    "D100",     # Missing docstring in public module
    "D101",     # Missing docstring in public class
    "D102",     # Missing docstring in public method
    "D103",     # Missing docstring in public function
    "D104",     # Missing docstring in public package
    "PT013",    # Allow importing fixtures from pytest to avoid repeating 'pytest' many times
]
[tool.ruff.lint.flake8-annotations]
allow-star-arg-any = true
ignore-fully-untyped = true
[tool.ruff.lint.isort]
known-first-party = ["esmvalcore"]
[tool.ruff.lint.pydocstyle]
convention = "numpy"
[tool.ruff.lint.pylint]
max-args = 7

[tool.pixi.dependencies]
aiohttp = "*"
cartopy = "*"
cf-units = "*"
cftime = "*"
dask = ">=2025"
dask-jobqueue = "*"
distributed = "*"
esgf-pyclient = ">=0.3.1"
esmvaltool-sample-data = "*"
filelock = "*"
fiona = "*"
fire = "*"
geopy = "*"
humanfriendly = "*"
intake-esgf = ">=2026.4.28"
intake-esm = "*"
iris = "*"
iris-esmf-regrid = ">=0.11.0"
iris-grib = ">=0.20.0"
isodate = ">=0.7.0"
jinja2 = "*"
libnetcdf = "!=4.9.1"
nc-time-axis = "*"
ncdata = "*"
nested-lookup = "*"
netcdf4 = "*"
numpy = "!=1.24.3"
packaging = "*"
pandas = "*"
pillow = "*"
pip = "!=21.3"
prov = "*"
psutil = "*"
py-cordex = "*"
pybtex = "*"
python = ">=3.12"
python-stratify = ">=0.3"
pyyaml = "*"
requests = "*"
rich = "*"
scipy = ">=1.6"
shapely = ">=2.0.0"
xarray = "*"
yamale = "*"
zarr = ">3"

[tool.pixi.workspace]
channels = ["conda-forge"]
platforms = ["linux-64", "osx-arm64"]

[tool.pixi.pypi-dependencies]
ESMValCore = { path = ".", editable = true }

[tool.pixi.environments]
default = { features = ["dev", "doc", "test"], solve-group = "default" }
esmvalcore = { solve-group = "default" }
# Environments for running tests with specific Python versions.
test-py312 = { features = ["py312", "test"], solve-group = "py312" }
test-py313 = { features = ["py313", "test"], solve-group = "py313" }
test-py314 = { features = ["py314", "test"], solve-group = "default" }
# Environment for testing R support
test-r = { features = ["test-r"], solve-group = "test-r" }

# Tools for running the tests.
[tool.pixi.feature.test.dependencies]
"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" = "*"

# Test R support
[tool.pixi.feature.test-r.dependencies]
"r-base" = "*"
"r-yaml" = "*"

# Tools for building the documentation.
[tool.pixi.feature.doc.dependencies]
"autodocsumm" = ">=0.2.2"
"ipython" = "*"
"myst-nb" = "*"
"sphinx" = ">=6.1.3,<9"
"pydata-sphinx-theme" = "*"

# Other development tools.
[tool.pixi.feature.dev.dependencies]
"jupyterlab" = "*"
"mypy" = "*"
"pre-commit" = "*"
"py-spy" = "*"
"ruff" = "*"

# Feature for running tests with Python 3.12.
[tool.pixi.feature.py312.dependencies]
"python" = "3.12.*"

# Feature for running tests with Python 3.13.
[tool.pixi.feature.py313.dependencies]
"python" = "3.13.*"

# Feature for running tests with Python 3.14.
[tool.pixi.feature.py314.dependencies]
"python" = "3.14.*"

# Tasks for use with `pixi run <task>`.
[tool.pixi.tasks]
test = {cmd = "pytest", description = "Run the tests"}
doc = {cmd = "sphinx-build doc html", description = "Build the documentation"}
