[tox]
envlist =
    py{311,312,313,313t,314,314t,dev}-test{,-recdeps,-docdeps,-alldeps,-oldestdeps,-devdeps,-devpytest,-predeps,-mpl380}{,-cov}{,-clocale}{,-fitsio}{,-noscipy}
    # Only these two exact tox environments have corresponding figure hash files.
    py311-test-image-mpl380-cov
    py311-test-image-mpldev-cov
    build_docs{,-predeps}
    linkcheck
    codestyle
    stubtest
requires =
    tox >=4.33 # for PEP 508 environment markers # keep in sync with pyproject.toml
    tox-uv

[testenv]
# Pass through the following environment variables which are needed for the CI
passenv = HOME,WINDIR,LC_ALL,LC_CTYPE,CC,CI,IS_CRON,ARCH_ON_CI,PY_COLORS,PYTHON_GIL,PYTHON_CONTEXT_AWARE_WARNINGS

setenv =
    NUMPY_WARN_IF_NO_MEM_POLICY = 1
    COVERAGE_CORE = sysmon; python_version >= '3.12'
    # For coverage, we need to pass extra options to the C compiler
    cov: CFLAGS = --coverage -fno-inline-functions -O0
    py313t: PYTHON_GIL=0
    image: MPLFLAGS = -m "mpl_image_compare" --mpl --mpl-generate-summary=html --mpl-results-path="{toxinidir}/results" --mpl-hash-library="{toxinidir}/astropy/tests/figures/{envname}.json" --mpl-baseline-path=https://raw.githubusercontent.com/astropy/astropy-figure-tests/astropy-main/figures/{envname}/ --remote-data
    !image: MPLFLAGS =
    clocale: LC_CTYPE = C.ascii
    clocale: LC_ALL = C
    devdeps: UV_INDEX = https://pypi.anaconda.org/liberfa/simple https://pypi.anaconda.org/scientific-python-nightly-wheels/simple
    mpldev: UV_INDEX = https://pypi.anaconda.org/scientific-python-nightly-wheels/simple
    devdeps, mpldev, predeps, devpytest: UV_INDEX_STRATEGY = unsafe-best-match # match pip's behavior
    fitsio: ASTROPY_ALWAYS_TEST_FITSIO = true
    # on oldestdeps, we let warnings be warnings (-Wdefault) instead of treated-as-errors,
    # so we don't need to deal with filtering anything triggered from dependencies
    # Other options replicate the static configuration from pyproject.toml, since they
    # would otherwise be shadowed by the env variable.
    oldestdeps: PYTEST_ADDOPTS = -Wdefault --doctest-rst --strict-config --strict-markers

# Run the tests in a temporary directory to make sure that we don't import
# astropy from the source tree
changedir = .tmp/{envname}

# tox environments are constructed with so-called 'factors' (or terms)
# separated by hyphens, e.g. test-devdeps-cov. Lines below starting with factor:
# will only take effect if that factor is included in the environment name. To
# see a list of example environments that can be run, along with a description,
# run:
#
#     tox -l -v
#
description =
    run tests
    recdeps: with recommended optional dependencies
    docdeps: with documentation dependencies
    alldeps: with all optional and test dependencies
    devdeps: with the latest developer version of key dependencies
    devpytest: with dev version of pytest infrastructure
    oldestdeps: with the oldest supported version of direct dependencies
    cov: and test coverage
    image: with image tests
    mpl380: with matplotlib 3.8.4
    mpldev: with the latest developer version of matplotlib
    double: twice in a row to check for global state changes
    noscipy: without scipy-dev

deps =
    # matplotlib 3.8 + pyparsing 3.3 = DeprecationWarning
    mpl380: matplotlib==3.8.4
    mpl380: pyparsing==3.2.5

    image: latex
    image, devpytest: scipy
    image: pytest-mpl>=0.18

    # Some FITS tests use fitsio as a comparison
    fitsio: fitsio

    # Include scipy in double run to detect test pollution in scipy-only tests
    double: scipy

    # The devdeps factor is intended to be used to install the latest developer version
    # or nightly wheel of key dependencies.
    devdeps-!noscipy: scipy>=0.0.dev0
    devdeps: numpy>=0.0.dev0
    devdeps-!noscipy: matplotlib>=0.0.dev0
    devdeps: pyerfa>=0.0.dev0

    mpldev: matplotlib>=0.0.dev0

    # Latest developer version of infrastructure packages.
    devpytest: git+https://github.com/pytest-dev/pytest.git
    devpytest: git+https://github.com/astropy/extension-helpers.git
    devpytest: git+https://github.com/scientific-python/pytest-doctestplus.git
    devpytest: git+https://github.com/astropy/pytest-remotedata.git
    devpytest: git+https://github.com/astropy/pytest-astropy-header.git
    devpytest: git+https://github.com/astropy/pytest-arraydiff.git
    devpytest: git+https://github.com/astropy/pytest-filter-subpackage.git
    devpytest: git+https://github.com/matplotlib/pytest-mpl.git
    devpytest: git+https://github.com/astropy/pytest-astropy.git

    # Duplicates test_all in pyproject.toml due to upstream bug
    # https://github.com/tox-dev/tox/issues/3433
    # But we cannot use alldeps because it messed up oldest-deps pins.
    devdeps-!noscipy: objgraph>=1.6.0
    devdeps-!noscipy: skyfield>=1.20
    devdeps-!noscipy: sgp4>=2.3
    devdeps-!noscipy: array-api-strict>=1.0
    devdeps-!noscipy: numpy-quaddtype>=0.2.2

# The following indicates which [project.optional-dependencies] from pyproject.toml will be installed.
# test_all does not work here due to upstream bug https://github.com/tox-dev/tox/issues/3433
extras =
    test: test
    recdeps: recommended
    alldeps, docdeps: all
    docdeps: docs

dependency_groups =
    alldeps: dataframe

commands =
    # docdeps-predeps: Override sphinx max pin in sphinx-design
    docdeps-predeps: uv pip install sphinx -U --pre --no-deps
    {list_dependencies_command}
    !cov-!double: pytest --strict-markers --pyargs astropy "{toxinidir}/docs" {env:MPLFLAGS} {posargs}
    cov-!double: pytest --strict-markers --pyargs astropy "{toxinidir}/docs" {env:MPLFLAGS} --cov astropy --cov-config="{toxinidir}/pyproject.toml" --cov-report xml:"{toxinidir}/coverage.xml" {posargs}

    double: pytest --keep-duplicates --strict-markers --pyargs astropy "{toxinidir}/docs" astropy "{toxinidir}/docs" {env:MPLFLAGS} {posargs}

pip_pre =
    devdeps: true
    predeps: true

uv_resolution =
    # The oldestdeps factor is intended to be used to install
    # the oldest versions of all dependencies.
    # Let uv handle this for us by requesting all requirements should be
    # resolved to their oldest compatible versions (including transitive dependencies)
    oldestdeps: lowest

# This lets developers use tox to build docs and ignores warnings.
# This is not used in CI; For that, we have RTD PR builder.
[testenv:build_docs{,-predeps}]
changedir = docs
description = invoke sphinx-build to build the HTML docs
extras =
  docs
  all
dependency_groups =
  dataframe

setenv =
    predeps: UV_INDEX_STRATEGY = unsafe-best-match # match pip's behavior

commands =
    # predeps: Override sphinx max pin in sphinx-design;
    # we need to reinstall sphinxcontrib-globalsubs, too as it either sphinx<9 or >=9
    predeps: uv pip install sphinx sphinxcontrib-globalsubs -U --pre
    {list_dependencies_command}
    sphinx-build \
    predeps: -W \
    -b html . _build/html {posargs:-j auto}
pip_pre =
    predeps: true

[testenv:linkcheck]
changedir = docs
description = check the links in the HTML docs
extras = docs
commands =
    {list_dependencies_command}
    sphinx-build -b linkcheck . _build/html {posargs:-W}

[testenv:codestyle]
skip_install = true
description = Run all style and file checks with pre-commit
deps =
    pre-commit
commands =
    pre-commit install-hooks
    pre-commit run {posargs:--color always --all-files --show-diff-on-failure}

[testenv:stubtest]
description = test automatically generated stubs for unit definition modules
allowlist_externals =
    touch
deps =
    mypy
commands =
    # We do not want to distribute py.typed files, but we need one or else Mypy
    # refuses to look at the generated stubs.
    touch {env_site_packages_dir}/astropy/units/py.typed
    stubtest --mypy-config-file .stubtest.ini \
        astropy.units.astrophys \
        astropy.units.cds \
        astropy.units.cgs \
        astropy.units.imperial \
        astropy.units.misc \
        astropy.units.photometric \
        astropy.units.required_by_vounit \
        astropy.units.si \
        astropy.units.function.units

[testenv:pyinstaller]
# Check that astropy can be included in a PyInstaller bundle without any issues. This
# also serves as a test that tests do not import anything from outside the tests
# directories with relative imports, since we copy the tests out to a separate directory
# to run them.
description = check that astropy can be included in a pyinstaller bundle
changedir = .pyinstaller
deps =
    pyinstaller
    pytest-mpl
    matplotlib
extras = test
commands =
    pyinstaller --onefile run_astropy_tests.py \
                --distpath . \
                --additional-hooks-dir hooks \
                --exclude-module tkinter \
                --collect-submodules=py \
                --hidden-import pytest \
                --hidden-import pytest_astropy.plugin \
                --hidden-import pytest_remotedata.plugin \
                --hidden-import pytest_doctestplus.plugin \
                --hidden-import pytest_mpl.plugin
    ./run_astropy_tests --astropy-root "{toxinidir}"
