[project]
name = "astropy"
dynamic = [
    "version"
]
description = "Astronomy and astrophysics core library"
readme = "README.rst"
authors = [
    { name = "The Astropy Developers", email = "astropy.team@gmail.com" }
]
license = "BSD-3-Clause"
license-files = ["LICENSE.rst", "licenses/*.rst"]
requires-python = ">=3.11"
classifiers = [
    "Intended Audience :: Science/Research",
    "Operating System :: OS Independent",
    "Programming Language :: C",
    "Programming Language :: Cython",
    "Programming Language :: Python :: 3 :: Only",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
    "Programming Language :: Python :: 3.13",
    "Programming Language :: Python :: 3.14",
    "Programming Language :: Python :: Implementation :: CPython",
    "Topic :: Scientific/Engineering :: Astronomy",
    "Topic :: Scientific/Engineering :: Physics",
]
keywords = [
    "astronomy",
    "astrophysics",
    "cosmology",
    "space",
    "science",
    "units",
    "table",
    "wcs",
    "samp",
    "coordinate",
    "fits",
    "modeling",
    "models",
    "fitting",
    "ascii",
]
dependencies = [
    "astropy-iers-data>=0.2026.5.18.1.11.28",
    "numpy>=2.0",
    "packaging>=25.0",
    "pyerfa>=2.0.1.3",  # for >=2.0.1.7, adjust structured_units.rst and doctest-requires
    "PyYAML>=6.0.0",
]

[project.optional-dependencies]
# Recommended run-time dependencies to enable a lot of functionality within Astropy.
recommended = [
    "scipy>=1.13",
    "matplotlib>=3.8.4",
    "narwhals>=1.42.0",  # keep in sync with dependency-groups.dataframe
]
# Optional IPython-related behavior is in many places in Astropy. IPython is a complex
# dependency that occasionally requires pinning one of it's upstream dependencies. If
# you are using Astropy from an IPython-dependent IDE, like Jupyter, this should enforce
# the minimum supported version of IPython.
ipython = [
    "ipython>=8.0.0",
]
jupyter = [  # these are optional dependencies for utils.console and table
    "astropy[ipython]",
    "ipywidgets>=7.7.3",
    "ipykernel>=6.16.0",
    "ipydatagrid>=1.1.13",
    # jupyter-core is a transitive dependency via ipykernel, we declare it as
    # a direct dependency in order to set a lower bound for oldest-deps testing
    "jupyter-core>=4.11.2",
    "pandas>=2.2.2",
]
# This is ALL the run-time optional dependencies.
all = [
    # Install grouped optional dependencies
    "astropy[recommended]",
    "astropy[ipython]",
    "astropy[jupyter]",
    # Install all remaining optional dependencies
    "certifi>=2022.6.15.1",
    "dask[dataframe]>=2024.8.0", # keep in sync with dependency-groups.dataframe
    "h5py>=3.11.0",
    "pyarrow>=16.0",
    "beautifulsoup4>=4.11.2", # imposed by pandas==2.2.2
    "html5lib>=1.1",
    "bleach>=3.2.1",
    "sortedcontainers>=2.1.0", # imposed by testing with hypothesis
    "pytz>=2016.10", # (older versions may work)
    "jplephem>=2.17.0",
    "mpmath>=1.2.1",
    "asdf-astropy>=0.7.0",
    "bottleneck>=1.4.0",
    "fsspec[http,s3]>=2023.4.0",  # keep in sync with dependency-groups.dataframe
    "s3fs>=2023.4.0",
    "uncompresspy>=0.4.0"
]
# The base set of test-time dependencies.
test = [
    "coverage>=7.2.0",
    "hypothesis>=6.84.0",
    "pytest>=8.0.1",
    "pytest-doctestplus>=1.4.0",
    "pytest-astropy-header>=0.2.1",
    "pytest-astropy>=0.11.0",
    "pytest-xdist>=3.6.0",
    "threadpoolctl>=3.0.0",
]
test_all = [
    # Install grouped optional dependencies
    "astropy[all]",  # installs all optional run-time dependencies
    "astropy[test]",
    # Install all remaining dependencies
    "objgraph>=3.1.2",
    "skyfield>=1.42.0",
    "sgp4>=2.22",
    "array-api-strict>=1.0",
    "array-api-strict<2.4;python_version<'3.12'",  # PYTHON_LT_3_12

    # 0.2.2 works on *some* platforms we support, though not all
    # 1.0.0 would be a more universal lower bound, but it also
    # requires numpy>=2.4. Because dependency trees are resolved
    # with *all* extras and groups (whether they are to be installed or not),
    # and we want to preserve the ability to test against NUMPY_LT_2_4,
    # we effectively cannot upgrade this lower bound until we drop NUMPY_LT_2_4
    "numpy-quaddtype>=0.2.2",
]
typing = [
    "pandas-stubs>=2.0.2",
    "scipy-stubs>=1.14.1.6",
    "narwhals>=1.42.0" # keep in sync with dependency-groups.dataframe
]
docs = [
    "astropy[recommended]",  # installs the [recommended] dependencies
    "sphinx>=8.2.0,<9",  # keep in sync with docs/conf.py
    "sphinx-astropy[confv3]>=1.11",
    "pytest>=8.0.0",
    "sphinx-changelog>=1.2.0",
    "sphinx_design>=0.6.1",
    "Jinja2>=3.1.3",
    "sphinxcontrib-globalsubs>=0.1.1",
    "matplotlib!=3.9.0",  # https://github.com/matplotlib/matplotlib/issues/28234
    "dask[dataframe]>=2024.8.0", # keep in sync with dependency-groups.dataframe
    "fsspec[http,s3]>=2023.4.0",  # keep in sync with dependency-groups.dataframe
]

[project.urls]
homepage = "https://www.astropy.org/"
documentation = "https://docs.astropy.org"
repository = "https://github.com/astropy/astropy"

[project.scripts]
fits2bitmap = "astropy.visualization.scripts.fits2bitmap:main"
fitscheck = "astropy.io.fits.scripts.fitscheck:main"
fitsdiff = "astropy.io.fits.scripts.fitsdiff:main"
fitsheader = "astropy.io.fits.scripts.fitsheader:main"
fitsinfo = "astropy.io.fits.scripts.fitsinfo:main"
samp_hub = "astropy.samp.hub_script:hub_script"
showtable = "astropy.table.scripts.showtable:main_deprecated"
showtable-astropy = "astropy.table.scripts.showtable:main"
volint = "astropy.io.votable.volint:main"
wcslint = "astropy.wcs.wcslint:main"

[build-system]
requires = ["setuptools>=77.0.0",
            "setuptools_scm>=8.0.0",
            "cython>=3.0.0, <4",
            "numpy>=2.0.0, <3",
            "extension-helpers>=1.4,<2",
            "pyerfa>=2.0.1.3"]
build-backend = "setuptools.build_meta"

[dependency-groups]
# a dev-only set of *tested* import/export target dataframe implementations
# that can be converted to and from via narwhals
dataframe = [
    # keep in sync with project.optional-dependencies.recommended
    # and project.optional-dependencies.all
    # and project.optional-dependencies.typing
    "narwhals>=1.42.0",
    "pyarrow>=16.0",
    "pandas>=2.2.2",
    "polars>=1.18.0",
    "duckdb>=1.1.0",
    "dask[dataframe]>=2024.8.0", # keep in sync with other declarations
]
# re-define historical optional dependencies (a.k.a. 'extras') as
# user-invisible, PEP 735 dependency groups
# These group together all the dependencies needed for developing in Astropy.
dev = [
    "astropy[recommended]",  # installs the most common optional dependencies
    "astropy[test]",
    "astropy[docs]",
    "astropy[typing]",
]
dev_all = [
    {include-group = "dev"},
    {include-group = "dataframe"},
    "astropy[test_all]",
    "tox>=4.33.0", # keep in sync with tox.minversion in tox.ini
]

[tool.setuptools]
include-package-data = true

[tool.setuptools.packages.find]
include = ["astropy*"]
namespaces = true

[tool.setuptools.package-data]
"*" = [
    "data/*",
    "data/*/*",
    "data/*/*/*",
    "data/*/*/*/*",
    "data/*/*/*/*/*",
    "data/*/*/*/*/*/*",
]
"astropy" = ["astropy.cfg", "CITATION"]
"astropy.cosmology" = ["*.ecsv"]
"astropy.tests.figures" = ["*.json"]
"astropy.wcs" = ["include/*/*.h"]
"astropy.wcs.tests" = ["extension/*.c"]

[tool.setuptools_scm]
version_file = "astropy/_version.py"

[tool.pytest.ini_options]
minversion = "8.0"
testpaths = [
    "astropy",
    "docs",
]
norecursedirs = [
    ".*",
    "docs[\\/]_build",
    "docs[\\/]generated",
    "astropy[\\/]extern",
]
astropy_header = true
doctest_plus = "enabled"
text_file_format = "rst"
remote_data_strict = true
addopts = [
    # keep in sync with tox.ini (oldestdeps's PYTEST_ADDOPTS)
    "--doctest-rst",
    "--strict-config",
    "--strict-markers",
    "-p no:legacypath",
]
log_cli_level = "info"
log_level = "INFO"
xfail_strict = true
filterwarnings = [
    "error",
    # https://github.com/astropy/astropy/issues/18126
    "ignore:'_UnionGenericAlias' is deprecated and slated for removal in Python 3.17:DeprecationWarning", # not PYTHON_LT_3_14
    # Weird warning from the vectorized do_format in Angle.to_string. low numpy/python?
    "ignore:invalid value encountered in do_format:RuntimeWarning",
    # https://github.com/astropy/astropy/issues/19511
    "ignore:Implicitly cleaning up <HTTPError 404:ResourceWarning",
    "ignore:unclosed <socket:ResourceWarning",
    "ignore:unclosed <ssl.SSLSocket:ResourceWarning",
]
doctest_norecursedirs = [
    "*/setup_package.py",
    "*/tests/command.py",
]
doctest_subpackage_requires = [
    "astropy/cosmology/_src/io/builtin/mapping.py = python>=3.12",  # not PYTHON_LT_3_12 (PR 17277)
    "astropy/cosmology/_src/io/builtin/row.py = python>=3.12",  # not PYTHON_LT_3_12 (PR 17277)
    "astropy/cosmology/_src/io/builtin/table.py = python>=3.12",  # not PYTHON_LT_3_12 (PR 17277)
    "astropy/table/table.py = python>=3.12",  # not PYTHON_LT_3_12 (PR 17277)
    "astropy/table/mixins/dask.py = dask",
    "docs/units/type_hints.rst = python<=3.13",  # PYTHON_LT_3_14 (PR 18140)
    "docs/units/structured_units.rst = pyerfa<2.0.1.7",  # PYERFA_LT_2_0_1_7
    "docs/timeseries/index.rst = numpy>=2.2.0",  # not NUMPY_LT_2_2 (PR 19509)
    "astropy/modeling/_fitting_parallel.py = dask",
    "docs/modeling/parallel-fitting.rst = dask",
    "docs/coordinates/example_gallery_plot_galactocentric_frame.rst = matplotlib",
    "docs/coordinates/example_gallery_plot_mars_coordinate_frame.rst = matplotlib",
    "docs/coordinates/example_gallery_plot_obs_planning.rst = matplotlib",
    "docs/coordinates/example_gallery_plot_sgr_coordinate_frame.rst = matplotlib",
    "docs/io/unified_table_hdf5.rst = h5py",
    "docs/io/unified_table_parquet.rst = pandas pyarrow",
]
markers = [
    "mpl_image_compare",
]

[tool.cibuildwheel]
# We disable testing for the following wheels:
# - MuslLinux (tests hang non-deterministically)
test-skip = "*-musllinux_x86_64"
enable = ["cpython-prerelease"] # this line can be removed when cibuildwheel is bumped to 3.1.0 or newer
skip = ["cp*t-*"] # https://github.com/astropy/astropy/issues/16916
environment-pass = ["EXTENSION_HELPERS_PY_LIMITED_API"]

[tool.cibuildwheel.macos]
archs = ["x86_64", "arm64"]

[tool.cibuildwheel.linux]
archs = ["auto", "aarch64"]


[tool.docformatter]
    # The ``summaries`` are not (yet) 75 characters because the summary lines can't be
    # automatically wrapped and must be re-written, which should be done at some point.
    recursive = true
    wrap-summaries = 1000
    wrap-descriptions = 75
    black = true
    syntax = "numpy"


[tool.coverage]

    [tool.coverage.run]
        omit = [
            "astropy/__init__*",
            "astropy/**/conftest.py",
            "astropy/**/setup*",
            "astropy/**/tests/*",
            "astropy/extern/*",
            "astropy/utils/compat/*",
            "astropy/version*",
            "astropy/wcs/docstrings*",
            "*/astropy/__init__*",
            "*/astropy/**/conftest.py",
            "*/astropy/**/setup*",
            "*/astropy/**/tests/*",
            "*/astropy/extern/*",
            "*/astropy/utils/compat/*",
            "*/astropy/version*",
            "*/astropy/wcs/docstrings*",
        ]

    [tool.coverage.report]
        exclude_also = [
            # Don't complain about packages we have installed
            "except ImportError",
            # Don't complain if tests don't hit defensive assertion code:
            "raise AssertionError",
            "raise NotImplementedError",
            "^\\s*case _ as unreachable:",
            # Don't complain about script hooks
            "'def main(.*):'",
            # Ignore branches that don't pertain to this version of Python
            "pragma: py{ignore_python_version}",
            # Don't complain about IPython completion helper
            "def _ipython_key_completions_",
            # typing.TYPE_CHECKING is False at runtime
            "if TYPE_CHECKING:", # TODO: drop this line when coverage>=7.10.1 is required
            # Ignore typing overloads
            "@overload",
        ]

[tool.ruff]
lint.extend-select = [
    "A",     # flake8-builtins
    "AIR",   # Airflow
    "ANN",   # flake8-annotations
    "ARG",   # flake8-unused-arguments
    "ASYNC", # flake8-async
    "B",     # flake8-bugbear
    "BLE",   # flake8-blind-except
    "C4",    # flake8-comprehensions
    "C90",   # mccabe
    "COM",   # flake8-commas
    # "CPY",   # flake8-copyright  # TODO: enable when out of preview
    "D",     # pydocstyle
    "DJ",    # flake8-django
    # "DOC",   # pydocstyle  # TODO: enable when out of preview
    "DTZ",   # flake8-datetimez
    "E",     # pycodestyle
    "EM",    # flake8-errmsg
    "ERA",   # Eradicate
    "EXE",   # flake8-executable
    "F",     # Pyflakes
    "FA",    # flake8-future-annotations
    "FBT",   # flake8-boolean-trap
    "FIX",   # flake8-fixme
    "FLY",   # flynt
    "FURB",  # refurb
    "G",     # flake8-logging-format
    "I",     # isort
    "ICN",   # flake8-import-conventions
    "INP",   # flake8-no-pep420
    "INT",   # flake8-gettext
    "ISC",   # flake8-implicit-str-concat
    "LOG",   # flake8-logging
    "N",     # pep8-naming
    "NPY",   # NumPy-specific rules
    "PERF",  # Perflint
    "PGH",   # pygrep-hooks
    "PIE",   # flake8-pie
    "PL",    # Pylint
    "PT",    # flake8-pytest-style
    "PTH",   # flake8-use-pathlib
    "PYI",   # flake8-pyi
    "Q",     # flake8-quotes
    "RET",   # flake8-return
    "RSE",   # flake8-raise
    "RUF",   # Ruff-specific rules
    "S",     # flake8-bandit
    "SIM",   # flake8-simplify
    "SLOT",  # flake8-slots
    "T10",   # flake8-debugger
    "T20",   # flake8-print
    "TD",    # flake8-todos
    "TID",   # flake8-tidy-imports
    "TRY",   # tryceratops
    "UP",    # pyupgrade
    "W",     # pycodestyle
    "YTT",   # flake8-2020
]
lint.ignore = [  # NOTE: non-permanent exclusions should be added to `.ruff.toml` instead.

    # flake8-builtins (A) : shadowing a Python built-in.
    # New ones should be avoided and is up to maintainers to enforce.
    "A00",

    # flake8-bugbear (B)
    "B008",  # FunctionCallArgumentDefault

    # flake8-commas (COM)
    "COM812",  # TrailingCommaMissing, conflicts with Ruff formatter
    "COM819",  # TrailingCommaProhibited, conflicts with Ruff formatter

    # pydocstyle (D)
    # Missing Docstrings
    "D102",  # Missing docstring in public method. Don't check b/c docstring inheritance.
    "D105",  # Missing docstring in magic method. Don't check b/c class docstring.
    # Whitespace Issues
    "D200",  # FitsOnOneLine
    # Quotes Issues
    "D300",  # triple-single-quotes, conflicts with Ruff formatter
    # Docstring Content Issues
    "D410",  # BlankLineAfterSection. Using D412 instead.
    "D400",  # EndsInPeriod.  NOTE: might want to revisit this.

    # pycodestyle (E, W)
    "E711",  # NoneComparison  (see unfixable)
    "E741",  # AmbiguousVariableName. Physics variables are often poor code variables

    # flake8-fixme (FIX)
    "FIX002",  # Line contains TODO | notes for improvements are OK iff the code works

    # pep8-naming (N)
    "N803",  # invalid-argument-name. Physics variables are often poor code variables
    "N806",  # non-lowercase-variable-in-function. Physics variables are often poor code variables

    # pandas-vet (PD)
    "PD",

    # pylint (PLC, PLR and PLW)
    "PLR1730", # if-stmt-min-max (not always clearer, and sometimes slower)
    "PLW0642", # self-or-cls-assignment (occasionally desirable, very rarely a mistake)

    # flake8-use-pathlib (PTH)
    "PTH123", # builtin-open (not worth creating a Path object, builtin open is fine)

    # flake8-quotes (Q)
    "Q000",  # use double quotes, conflicts with Ruff formatter

    # flake8-return (RET)
    # RET can sometimes help find places where refactoring is very helpful,
    # but enforcing it everywhere might create undesirable churn
    "RET505",  # superfluous-else-return
    "RET506",  # superfluous-else-raise

    # Ruff-specific rules (RUF)
    "RUF005",  # unpack-instead-of-concatenating-to-collection-literal -- it's not clearly faster.

    # flake8-simplify (SIM)
    "SIM103", # needless-bool (cannot be safely applied in all contexts (np.True_ is not True))

    # flake8-self (SLF)
    "SLF001", # private member access

    # flake8-todos (TD)
    "TD002",  # Missing author in TODO
]
exclude = [
    "astropy/extern/*",
    "*_parsetab.py",
    "*_lextab.py"
]

[tool.ruff.lint.extend-per-file-ignores]
"setup.py" = ["INP001"]  # Part of configuration, not a package.
".github/workflows/*.py" = ["INP001"]
"astropy/config/_tempfile_shim.py" = ["UP032", "PLE0704", "PTH"]
"astropy/modeling/models/__init__.py" = ["F405"]
"astropy/utils/decorators.py" = [
    "D214", "D215",  # keep Examples section indented.
    "D411",  # sphinx treats spaced example sections as real sections
]
"test_*.py" = [
    "ANN201",  # Public function without return type annotation
    "B018",  # UselessExpression
    "D",  # pydocstyle
    "S101",  # Use of assert detected
]
".pyinstaller/*.py" = ["INP001"]  # Not a package.
"conftest.py" = ["INP001"]  # Part of configuration, not a package.
"docs/*.py" = [
    "INP001",  # implicit-namespace-package. The examples are not a package.
]
"__init__.py" = [
    "E402", # module level import not at top of file
    "F403", # Wildcard imports
]

[tool.ruff.lint.flake8-annotations]
ignore-fully-untyped = true
mypy-init-return = true

[tool.ruff.lint.flake8-comprehensions]
allow-dict-calls-with-keyword-arguments = true

[tool.ruff.lint.isort]
known-first-party = ["astropy", "extension_helpers"]

[tool.ruff.lint.pydocstyle]
convention = "numpy"

[tool.repo-review]
ignore = [
    "MY",    # ignore MyPy setting checks
    "PC111", # ignore using `blacken-docs` in pre-commit
    "PC140", # ignore using `mypy` in pre-commit
    "PC180", # ignore using `prettier` in pre-commit
    "PC901", # ignore using custom update message (we have many of the default ones in our history already)
    "PP308", # ignore requiring `-ra` flag for pytest, astropy's test suite is too large for this to be useful
    "PY005", # ignore requiring a root level "test*" directory
]

[tool.towncrier]
    package = "astropy"
    filename = "CHANGES.rst"
    directory = "docs/changes"
    underlines = "=-^"
    template = "docs/changes/template.rst"
    title_format = "Version {version} ({project_date})"

    [[tool.towncrier.type]]
        directory = "feature"
        name = "New Features"
        showcontent = true

    [[tool.towncrier.type]]
        directory = "api"
        name = "API Changes"
        showcontent = true

    [[tool.towncrier.type]]
        directory = "bugfix"
        name = "Bug Fixes"
        showcontent = true

    [[tool.towncrier.type]]
        directory = "perf"
        name = "Performance Improvements"
        showcontent = true

    [[tool.towncrier.type]]
        directory = "other"
        name = "Other Changes and Additions"
        showcontent = true

    [[tool.towncrier.section]]
        name = ""
        path = ""

    [[tool.towncrier.section]]
        name = "astropy.config"
        path = "config"

    [[tool.towncrier.section]]
        name = "astropy.constants"
        path = "constants"

    [[tool.towncrier.section]]
        name = "astropy.convolution"
        path = "convolution"

    [[tool.towncrier.section]]
        name = "astropy.coordinates"
        path = "coordinates"

    [[tool.towncrier.section]]
        name = "astropy.cosmology"
        path = "cosmology"

    [[tool.towncrier.section]]
        name = "astropy.extern"
        path = "extern"

    [[tool.towncrier.section]]
        name = "astropy.io.ascii"
        path = "io.ascii"

    [[tool.towncrier.section]]
        name = "astropy.io.fits"
        path = "io.fits"

    [[tool.towncrier.section]]
        name = "astropy.io.misc"
        path = "io.misc"

    [[tool.towncrier.section]]
        name = "astropy.io.registry"
        path = "io.registry"

    [[tool.towncrier.section]]
        name = "astropy.io.votable"
        path = "io.votable"

    [[tool.towncrier.section]]
        name = "astropy.modeling"
        path = "modeling"

    [[tool.towncrier.section]]
        name = "astropy.nddata"
        path = "nddata"

    [[tool.towncrier.section]]
        name = "astropy.samp"
        path = "samp"

    [[tool.towncrier.section]]
        name = "astropy.stats"
        path = "stats"

    [[tool.towncrier.section]]
        name = "astropy.table"
        path = "table"

    [[tool.towncrier.section]]
        name = "astropy.tests"
        path = "tests"

    [[tool.towncrier.section]]
        name = "astropy.time"
        path = "time"

    [[tool.towncrier.section]]
        name = "astropy.timeseries"
        path = "timeseries"

    [[tool.towncrier.section]]
        name = "astropy.uncertainty"
        path = "uncertainty"

    [[tool.towncrier.section]]
        name = "astropy.units"
        path = "units"

    [[tool.towncrier.section]]
        name = "astropy.utils"
        path = "utils"

    [[tool.towncrier.section]]
        name = "astropy.visualization"
        path = "visualization"

    [[tool.towncrier.section]]
        name = "astropy.wcs"
        path = "wcs"

[tool.gilesbot]
    [tool.gilesbot.circleci_artifacts]
        enabled = true

    [tool.gilesbot.pull_requests]
        enabled = true

    [tool.gilesbot.towncrier_changelog]
        enabled = true
        verify_pr_number = true
        changelog_skip_label = "no-changelog-entry-needed"
        help_url = "https://github.com/astropy/astropy/blob/main/docs/changes/README.rst"
        changelog_missing_long = "There isn't a changelog file in this pull request. Please add a changelog file to the `changelog/` directory following the instructions in the changelog [README](https://github.com/astropy/astropy/blob/main/docs/changes/README.rst)."
        type_incorrect_long = "The changelog file you added is not one of the allowed types. Please use one of the types described in the changelog [README](https://github.com/astropy/astropy/blob/main/docs/changes/README.rst)"
        number_incorrect_long = "The number in the changelog file you added does not match the number of this pull request. Please rename the file."

    [tool.gilesbot.circleci_artifacts.py311-test-image-mpl380]
        url = ".tmp/py311-test-image-mpl380/results/fig_comparison.html"
        message = "Click details to see the figure test comparisons, for py311-test-image-mpl380."
        report_on_fail = true

    [tool.gilesbot.circleci_artifacts.py311-test-image-mpldev]
        url = ".tmp/py311-test-image-mpldev/results/fig_comparison.html"
        message = "Click details to see the figure test comparisons for py311-test-image-mpldev."
        report_on_fail = true

[tool.codespell]
skip = """
    *.cff,
    */data/*,
    *extern/*,
    astropy/CITATION,
    docs/credits.rst,
    *_lextab.py,
    *_parsetab.py,
    astropy/wcs/tests/test_wcs.py
"""
# The following list of words for codespell to ignore may contain some
# misspellings that should be revisited and fixed in the future.
ignore-words-list = """
    aas,
    ans,
    clen,
    coo,
    datas,
    ded,
    dum,
    fo,
    hel,
    lightyear,
    lond,
    nax,
    nd,
    ned,
    nin,
    numer,
    precess,
    precessed,
    precesses,
    precessing,
    pres,
    som,
    splitted,
    stil,
    te,
    wirth,
"""

[tool.uv]
# never build the following packages from source. Prefer more recent versions
# with binary distributions even with --resolution=lowest[-direct]
no-build-package = [
    "bottleneck",
    "coverage",
    "h5py",
    "numpy",
    "pandas",
    "polars",
    "requests",
    "scipy",
    # "sgp4", # https://github.com/brandon-rhodes/python-sgp4/pull/150

    # via jsonschema v4.0.1 via asdf v2.15.0 via asdf-astropy v0.8.0
    "pyrsistent", # can be removed once we drop asdf-astropy<=0.8 https://github.com/astropy/asdf-astropy/pull/297

    # via fsspec
    "aiohttp",
    "frozenlist", # indirect (via aiohttp)

    # via ipython
    "backcall", # can be removed once ipython<8.17 is dropped
    "pickleshare", # can be removed once ipython<8.17 is dropped
    "ptyprocess", # indirect (via pexpect 4.3.1) https://github.com/pexpect/pexpect/pull/822
    "pure-eval", # indirect (via stack-data 0.6.0) https://github.com/alexmojaki/stack_data/pull/61
    "wcwidth", # indirect (via w 3.0.41) https://github.com/prompt-toolkit/python-prompt-toolkit/pull/2036
    "path.py", # indirect (via pickleshare 0.6) # can be removed once ipython<8.17 is dropped

    # via ipywidgets
    "jinja2", # indirect (via nbconvert 4.0.0 and notebook 4.0.1)
    "mistune", # indirect (via nbconvert 4.0.0)
    "terminado", # indirect (via notebook 4.0.1 via widgetsnbextension 3.6.0)
    "markupsafe", # indirect (via jinja2 2.11.3)

    # via ipykernel
    "appnope",
    "psutil",
    "pyzmq",
    "tornado",

    # via matplotlib
    "contourpy",
    "kiwisolver",
    "matplotlib",
    "pillow",
    "pyparsing",

    # via dask
    "locket", # indirect (via partd 1.4.0)
    "toolz",

    # via bleach and html5lib (both unmaintained)
    "webencodings",

    # via s3fs
    "wrapt", # indirect (via aiobotocore 2.5.0)
    "yarl", # indirect (via aiohttp 3.8.3 via aiobotocore 2.5.0)
    "multidict", # indirect (via aiohttp 3.8.3 via aiobotocore 2.5.0)

    # via sphinx-astropy
    "numpydoc",

    # the following *may* be visited during env resolution, although
    # they are not expected to land in the final solution,
    # even with --resolution=lowest
    "cffi",
    "joblib",
]

# ensure that uv resolves envs that are compatible with macOS arm64,
# even in drastic conditions like --resolution=lowest[-direct],
# taking into account tool.uv.no-build-package
required-environments = [
    "sys_platform == 'darwin' and platform_machine == 'arm64'",
]

# constrain acceptable versions of some known-problematic, indirect dependencies
constraint-dependencies = [
    "asdf>=2.15.1",
    "asdf-coordinates-schemas>=0.2.0",

    # via pytest
    # iniconfig 1.0.1 is the first version with proper wheels
    # this constraint can be removed once pytest>=9.0 is required
    "iniconfig>=1.0.1",

    # reproduce IPython minimal requirements on its dependencies
    # as of version 9.7.0 (dev), the earliest time at which lower bounds
    # started being consistently declared and tested.
    # This entire chunk may be removed when we drop support for IPython<9.7
    'colorama>=0.4.4; sys_platform == "win32"',
    "decorator>=4.3.2",
    "ipython-pygments-lexers>=1.0.0",
    "jedi>=0.18.1",
    "matplotlib-inline>=0.1.5",
    'pexpect>4.3; sys_platform != "win32" and sys_platform != "emscripten"',
    "prompt_toolkit>=3.0.41",
    "pygments>=2.11.0",
    "stack_data>=0.6.0",
    "traitlets>=5.13.0",
    "typing_extensions>=4.6; python_version<'3.12'",

    # via ipython (can be removed once ipython<8.17 is dropped)
    "pickleshare>=0.7.5",

    # via ipykernel (indirect) oldestdeps
    "py>=v1.11.0", # workaround a portability issue with oldestdeps resolution

    # via beautifulsoup4
    # can be dropped once we only support versions of pandas
    # requiring beautifulsoup4>=4.14.3
    "soupsieve>=1.6.1",

    # via matplotlib
    # can be removed once mpl>=3.10.7 is min
    "pyparsing>=2.4.0",

    # via dask
    "toolz>=0.12.0", # can be removed once dask<=2025.11.0 is dropped
    "cloudpickle>=2.1.0", # can be removed once dask<2024.8.1 is dropped

    # see https://github.com/astropy/astropy/issues/18292
    "array-api-strict<2.4 ; python_version<'3.12'",
]

# uv sync's default behavior includes the 'dev' group.
# Disable this so we get lightweight envs by default.
default-groups = []
